C++ 函数中的字符串文本:自动变量还是在堆中分配?

C++ 函数中的字符串文本:自动变量还是在堆中分配?,c++,c,memory,memory-management,memory-leaks,C++,C,Memory,Memory Management,Memory Leaks,我们在函数中使用的字符串文字是自动变量吗?或者它们被分配到我们必须手动释放的堆中 我有一个类似下面所示的代码的情况,其中我将一个字符串文本分配给类的一个私有字段(在代码中标记为1),并在以后的程序中检索它并使用它(标记为2)。我是否将堆栈中的变量指定给其中一个字段?代码是否可以引用一个悬空指针,在本例中,该指针可以工作,因为程序足够小 我已经编译并运行了它,它运行得很好,但是我在实际的程序中遇到了一个奇怪的崩溃,我将字符串文本分配给类的字段,就像这样,我怀疑我上面提到的情况 #include &

我们在函数中使用的字符串文字是自动变量吗?或者它们被分配到我们必须手动释放的堆中

我有一个类似下面所示的代码的情况,其中我将一个字符串文本分配给类的一个私有字段(在代码中标记为1),并在以后的程序中检索它并使用它(标记为2)。我是否将堆栈中的变量指定给其中一个字段?代码是否可以引用一个悬空指针,在本例中,该指针可以工作,因为程序足够小

我已经编译并运行了它,它运行得很好,但是我在实际的程序中遇到了一个奇怪的崩溃,我将字符串文本分配给类的字段,就像这样,我怀疑我上面提到的情况

#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.