代码之家  ›  专栏  ›  技术社区  ›  Srikanth

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

  •  3
  • Srikanth  · 技术社区  · 16 年前

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

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

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

    #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 回复  |  直到 16 年前
        1
  •  9
  •   Serafina Brocious    16 年前

    字符串文本将由编译器放置在二进制文件的初始化数据或文本(代码)段中,而不是驻留在(运行时分配的)内存或堆栈中。所以您应该使用指针,因为您将引用编译器已经为您生成的字符串文本。注意,修改这个(通常需要更改内存保护)将改变这个文本的所有使用。

        2
  •  6
  •   Richard Corden    16 年前

    修改字符串文字是未定义的行为,并且最有可能是程序崩溃的原因(ISO C++:2.134/2)。标准允许从字符串文本到 char* 为了向后兼容C,如果您绝对需要的话,您的代码中应该只有这个转换。

    如果希望将字符串文字视为常量,则可以将成员的类型更改为 const char * .

    如果你的设计要求 s 可以修改,那么我建议将其类型更改为 std::string .

        3
  •  1
  •   Srikanth    16 年前

    谢谢科迪和理查德。

    我找到了虫子的原因。这是因为我在删除一个已经删除的对象。我在做:

    if (obj != NULL) delete obj;
    

    我把它改成:

    if (obj != NULL)
    {
        delete obj;
        obj = NULL;
    }
    

    学习C++绝对有趣:

        4
  •  0
  •   Treb    16 年前

    可能导致崩溃的原因是您没有0-终止字符串?

        5
  •  0
  •   Community CDub    8 年前

    让我们看看你的选择。
    您还应该做以下几件事:

        /*
         * 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::string是自动初始化为空字符串的。所有分配的内存都被正确地取消分配。它可以很容易地作为可修改版本和不可修改版本返回。它也很容易操作( 增大收缩变化)。如果增加了C字符串,则需要重新分配内存并将字符串复制到新内存等(这非常耗时,而且容易出错)。

    为了处理动态分配对象,我将了解智能指针。
    有关智能指针的详细信息,请参阅本文。
    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.