我们在里面使用的字符串文字是自动变量吗?或者它们是否在堆中分配,我们必须手动释放?
我的情况类似于下面显示的代码,其中我将字符串文字分配给类的私有字段(在代码中标记为ONE),并在稍后的程序中检索它并使用它(标记为二)。我是否将堆栈中的变量分配给ONE中的字段?代码是否可以引用悬空指针,在这种情况下,由于程序足够小,它可以工作吗?
我已编译并运行它,它工作正常,但我在我的实际程序中遇到了一个奇怪的崩溃,我将字符串文字分配给类的字段,我怀疑上面提到的情况。< / p>
#include <iostream>
using namespace std;
class MemoryLeak
{
private:
char *s;
public:
MemoryLeak() {}
void store()
{
s = "Storing a string"; // ONE
}
char *retrieve()
{
return s;
}
};
int main()
{
MemoryLeak *obj = new MemoryLeak();
obj->store();
cout << obj->retrieve() << endl; // TWO
delete obj;
return 0;
}
我应该将变量“s”声明为char数组而不是指针吗?我打算使用std :: string,但我只是对此感到好奇。
任何指针或帮助一如既往地非常感谢:)谢谢。
答案 0 :(得分:9)
字符串文字将由编译器放置在二进制文件的初始化数据或文本(代码)段中,而不是驻留在(运行时分配的)内存或堆栈中。因此,您应该使用指针,因为您将引用编译器已为您生成的字符串文字。请注意,修改此项(通常需要更改内存保护)将更改此文字的所有用法。
答案 1 :(得分:6)
修改字符串文字是未定义的行为,很可能是程序崩溃的原因(ISO C ++:2.13.4 / 2)。该标准允许从字符串文字转换为char*
以向后兼容C,如果您绝对需要,您应该只在代码中进行转换。
如果您希望将字符串文字视为常量,则可以将成员的类型更改为const char *
。
如果您的设计要求s
可以修改,那么我建议将其类型更改为std::string
。
答案 2 :(得分:1)
谢谢Cody和Richard。
我找到了错误的原因。这是因为我正在对已经删除的对象进行删除。我在做:
if (obj != NULL) delete obj;
我把它改为:
if (obj != NULL)
{
delete obj;
obj = NULL;
}
学习C ++绝对有趣:)
答案 3 :(得分:0)
可能导致崩溃的原因是你没有0终止字符串?
答案 4 :(得分:0)
让我们来看看你的选择 你还应该做几件事:
/*
* Should initialize s to NULL or a valid string in constructor */
MemoryLeak()
{
store();
}
void store()
{
// This does not need to be freed because it is a string literal
// generated by the compiler.
s = "Storing a string"; // ONE
// Note this is allowed for backward compatibility but the string is
// really stored as a const char* and thus unmodifiable. If somebody
// retrieves this C-String and tries to change any of the contents the
// code could potentially crash as this is UNDEFINED Behavior.
// The following does need to be free'd.
// But given the type of s is char* this is more correct.
s = strdup("Storing a string");
// This makes a copy of the string on the heap.
// Because you allocated the memory it is modifiable by anybody
// retrieving it but you also need to explicitly de-allocate it
// with free()
}
您正在使用的是C-Strings。这些不应该与C ++ std :: string混淆。 C ++ std :: string自动初始化为空字符串。分配的任何内存都已正确分配。它可以很容易地作为可修改和不可修改的版本返回。它也易于操作(即增长缩小变化)。如果你增长了一个C-String,你需要重新分配内存并将字符串复制到新的内存等(这很容易出错)。
为了应对动态分配你的对象,我会学习智能指针 有关智能指针的更多详细信息,请参阅此文章 Smart Pointers or who owns you Baby
std::auto_ptr<MemoryLeak> obj(new MemoryLeak());
obj->store();
std::cout << obj->retrieve() << std::endl; // TWO
// No need to delete When object goes out of scope it auto deletes the memory.