为什么字符串文字在这里被重写了(C++)



我有一个类,里面有一个指针。我在这里只包含了骨架代码。类构造函数需要一个字符串。

#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;
}

该程序的输出为:

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

我在等

foo
bar

这是怎么回事?对象a的指针是如何被覆盖的?

这里发生了什么?对象a的指针是如何被覆盖的?

您正在经历未定义的行为。

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

这里string s是输入字符串的副本,并且在构造函数的持续时间内有效。因此,s.data()在构造函数完成后挂起。

std::string对象在超出作用域时调用其析构函数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
}

之后,当您实际打印该值时,data_已经被销毁,之后您对其所做的操作会导致未定义的行为(这意味着输出字符串时程序的行为可以是任何东西,因此术语未定义(。


因为这个问题已经回答了。我不妨给出一个合理的解决方案。

解决方案:创建一个字符串临时保存在类中的副本,并在类超出范围时将其销毁:

示例:

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_;
};

a和b是从临时字符串对象创建的。当这些字符串对象在语句结束时被销毁时,它们会释放内存,并且指向字符所在位置的底层char*将变为无效。通常不能使用从这样的字符串中提取的char*。

最新更新