简体   繁体   English

为什么在此处覆盖字符串文字(C++)?

[英]Why is a string literal being over written here (C++)?

I have a class holding a pointer.我有一个 class 持有一个指针。 I have only included skeleton code here.我在这里只包含了骨架代码。 The class constructor expects a string. class 构造函数需要一个字符串。

#include <iostream>
#include <string>

using namespace std;

class slice {
public:
slice(string s):
    data_(s.data()),
    size_(s.size()) {}

    const string toString() {
        string res(data_, data_+size_);
        return res;
    }

private:
    const char* data_;
    const size_t size_;
};

int main() {

    slice a{"foo"};
    slice b{"bar"};


    cout << a.toString() << endl;
    cout << b.toString() << endl;
}

The output of this program is:该程序的output为:

$ g++ test.cpp && ./a.out 
bar
bar

I am expecting我期待

foo
bar

What is going on here?这里发生了什么? How is the pointer held by object a being overwritten? object a 持有的指针如何被覆盖?

What is going on here?这里发生了什么? How is the pointer held by object a being overwritten? object a 持有的指针如何被覆盖?

You are experiencing undefined behavior .您正在经历未定义的行为

slice(string s):
    data_(s.data()),
    size_(s.size()) {}

Here string s is a copy of the input string and lives for the duration of the constructor.这里string s是输入字符串的副本,并在构造函数的持续时间内存在。 Hence s.data() dangles after the constructor is finished.因此s.data()在构造函数完成后悬空。

a and b are being created from temporary string objects. a 和 b 是从临时字符串对象创建的。 When those string objects are destroyed by the end of the statement, they deallocate their memory, and the underlying char* pointing to where the characters were becomes invalid.当这些字符串对象在语句结束时被销毁时,它们会释放它们的 memory,并且指向字符所在位置的底层 char* 变得无效。 You can't usually use a char* taken from a string like this.您通常不能使用从这样的字符串中获取的 char* 。

The std::string objects calls its destructor std::~string() when it goes out of scope. std::string对象在超出 scope 时调用其析构函数std::~string()

slice(string s) : data_(s.data()), size_(s.size()) {
    // After this function is called, the string goes out of scope and s.data() is deallocated by the destructor.
    // Leaving gibberish value inside of 'data_' member
}

Afterwards, when you actually print the value, data_ was already destroyed by then and what you do with it afterwards results in Undefined Behavior (It means the behavior of the program when outputting the string can be anything, thus the term undefined ).之后,当您实际打印该值时, data_到那时已经被销毁,然后您对它所做的事情会导致未定义的行为(这意味着输出字符串时程序的行为可以是任何东西,因此术语undefined )。


Since this question has already been answered.因为这个问题已经回答了。 I might as well give a reasonable solution.我不妨给出一个合理的解决方案。

Solution: Create a copy of what the string is holding temporarily inside your class and destroy it when your class goes out of scope:解决方案:创建一个临时保存在 class 中的字符串的副本,并在 class 超出 scope 时将其销毁:

Example:例子:

class slice {
public:
    slice(string s):
        size_(s.size()) {
        // Dynamically allocate a new string so that it doesn't get deleted when it goes out of scope
        data_ = new char[s.size()];
        // Copy the data into the newly allocated string
        s.copy(data_, s.size());
    }

    slice(const slice&) = default; // Copy constructor
    slice(slice&&) = default;      // Move constructor

    // Destructor
    ~slice() {
        delete[] data_;
    }

    const string toString() {
        // Now 'data_' retains its value even after the string is destroyed
        string res(data_, data_+size_);
        return res;
    }

private:
    char* data_;
    const size_t size_;
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM