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

时间:2008-10-06 09:29:41

标签: c++ c memory memory-management memory-leaks

我们在里面使用的字符串文字是自动变量吗?或者它们是否在堆中分配,我们必须手动释放?

我的情况类似于下面显示的代码,其中我将字符串文字分配给类的私有字段(在代码中标记为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,但我只是对此感到好奇。

任何指针或帮助一如既往地非常感谢:)谢谢。

5 个答案:

答案 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.