我有一个类,里面有一个指针。我在这里只包含了骨架代码。类构造函数需要一个字符串。
#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*。