C++ 函数中的字符串文本:自动变量还是在堆中分配?
我们在函数中使用的字符串文字是自动变量吗?或者它们被分配到我们必须手动释放的堆中 我有一个类似下面所示的代码的情况,其中我将一个字符串文本分配给类的一个私有字段(在代码中标记为1),并在以后的程序中检索它并使用它(标记为2)。我是否将堆栈中的变量指定给其中一个字段?代码是否可以引用一个悬空指针,在本例中,该指针可以工作,因为程序足够小 我已经编译并运行了它,它运行得很好,但是我在实际的程序中遇到了一个奇怪的崩溃,我将字符串文本分配给类的字段,就像这样,我怀疑我上面提到的情况C++ 函数中的字符串文本:自动变量还是在堆中分配?,c++,c,memory,memory-management,memory-leaks,C++,C,Memory,Memory Management,Memory Leaks,我们在函数中使用的字符串文字是自动变量吗?或者它们被分配到我们必须手动释放的堆中 我有一个类似下面所示的代码的情况,其中我将一个字符串文本分配给类的一个私有字段(在代码中标记为1),并在以后的程序中检索它并使用它(标记为2)。我是否将堆栈中的变量指定给其中一个字段?代码是否可以引用一个悬空指针,在本例中,该指针可以工作,因为程序足够小 我已经编译并运行了它,它运行得很好,但是我在实际的程序中遇到了一个奇怪的崩溃,我将字符串文本分配给类的字段,就像这样,我怀疑我上面提到的情况 #include &
#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;
}
#包括
使用名称空间std;
类存储器
{
私人:
char*s;
公众:
MemoryLeak(){}
无效存储()
{
s=“存储字符串”;//一个
}
char*retrieve()
{
返回s;
}
};
int main()
{
MemoryLeak*obj=新的MemoryLeak();
obj->store();
cout retrieve()字符串文本将由编译器放置在二进制文件的初始化数据或文本(代码)段中,而不是驻留在(运行时分配的)中内存或堆栈。因此,您应该使用指针,因为您将引用编译器已经为您生成的字符串文字。请注意,修改此项(通常需要更改内存保护)将更改此文本的所有用途。可能导致崩溃的原因是您没有0-终止字符串?修改字符串文本是未定义的行为,很可能是程序崩溃的原因(ISO C++:2.13.4/2)。该标准允许从字符串文字转换为char*
,以向后兼容C,并且只有在绝对需要时,才应在代码中进行该转换
如果希望将字符串文字视为常量,则可以将成员的类型更改为const char*
如果您的设计要求可以修改s
,那么我建议将其类型更改为std::string
谢谢Cody和Richard
我找到了错误的原因。这是因为我正在对已删除的对象执行删除操作。我正在执行:
if (obj != NULL) delete obj;
我把它改成:
if (obj != NULL)
{
delete obj;
obj = NULL;
}
学习C++肯定是有趣的: < P>让我们看看你的选择。
您还应该做几件事:
/*
* 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字符串。这些不应该与C++ STD::string混淆。C++ STD::字符串是自动初始化为空字符串的。分配的任何内存都被正确分配。它可以很容易地被归还为可修改和不可修改的版本。它也很容易操作(即增长收缩变化)。。如果您增长一个C字符串,则需要重新分配内存并将该字符串复制到新内存中等(这非常耗时,而且容易出错)
为了处理动态分配对象的问题,我将学习智能指针。
有关智能指针的更多详细信息,请参阅本文。
std::auto_ptr obj(新的MemoryLeak());
obj->store();
std::cout retrieve()呃,字符串文本总是以null结尾。这取决于编译器,不是吗?除非你正在处理30年前的编译器:PYes-很有趣!关于你发现的错误,我真的建议你使用智能指针。搜索“智能指针”和“RAII”在StackOverflow中,您会发现有用的信息。智能指针负责为您管理对象的生存期。删除应该在析构函数中完成。可能在赋值中完成,但即使在那里复制到临时和交换通常也更安全(临时的析构函数清除交换的旧值)@理查德:我会看看智能指针和RAII。@onebyone.livejournal.com:谢谢。我会在代码中删除之前删除空检查。但正如理查德指出的,智能指针似乎是一个更好的选择,但不是在我学会之前:)@MSalters:我不确定我是否理解你:(修改它是非法的。它实际上是一个const char*+1到const char*。MemoryLeak::s应该是const,应该是const char*MemoryLeak::retrieve()
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.