【问题标题】:Possible memory leak with malloc, struct, std::string, and freemalloc、struct、std::string 和 free 可能存在内存泄漏
【发布时间】:2011-11-28 10:15:11
【问题描述】:

我有类似以下的情况,我不确定结构的 std::string 元素是否泄漏内存,或者这是否正常。调用free(v)时,这两个std::strings分配的内存是否被删除?

struct MyData
{
    std::string s1;
    std::string s2;
};

void* v = malloc(sizeof(MyData));

...

MyData* d = static_cast<MyData*>(v);
d->s1 = "asdf";
d->s2 = "1234";

...

free(v);

泄漏与否?

我使用 void-pointer 是因为我有另一个高级结构,它由一个枚举和一个 void-pointer 组成。根据枚举变量的值,void* 将指向不同的数据结构。

例子:

enum-field has EnumValue01 => void-pointer 将指向一个 malloc 的 MyData01 结构

枚举字段有 EnumValue02 => void-pointer 将指向一个 malloc 的 MyData02 结构

当然,我们非常感谢您对不同方法的建议。

【问题讨论】:

  • 看起来你正在以某种方式重新发明多态性。您知道 C++ 中可用的所有现代编程技术吗?您使用malloc/free 表明您没有。
  • 不同的数据结构没有任何共同点。所以我想到了使用枚举和void*创建一个空的纯虚拟基类并让所有数据结构继承该基类会更好吗?
  • 如果不知道你的具体情况就无法真正判断,但是如果这些结构要存储在同一个上层结构中,它们确实有一些共同点 ;)

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


【解决方案1】:

您不应该在 C++ 程序中使用 malloc()free();它们不支持构造函数/析构函数。

使用newdelete 运算符。

【讨论】:

    【解决方案2】:

    这是未定义的行为 - malloc() 分配的内存未初始化,因此将其用作包含 string 对象的结构可能会导致任何事情;我预计会崩溃。由于在调用free() 之前没有人调用析构函数,string 对象不会被销毁,它们的缓冲区几乎肯定会泄漏。

    【讨论】:

    • 不能用placement new操作符在新分配的*d中初始化s1和s2吗?
    • @Alex:是的,你可以,但你必须自己处理可能的例外情况。
    • @Alex 您可以使用placement new 在malloc'd 内存中构造MyData。在这种情况下,您还需要在free内存之前显式调用~MyData()
    【解决方案3】:

    确实有泄漏。 free 不会调用 MyData 析构函数(毕竟它是一个 C 函数,对 C++ 的东西一无所知)。要么你应该使用 new/delete 而不是 malloc/free:

    MyData* d = new MyData; d->s1 = "asdf"; d->s2 = "1234"; delete d;

    或者自己调用析构函数:

    void* v = malloc(sizeof(MyData)); MyData* d = new (v) MyData; // use placement new instead of static_cast d->s1 = "asdf"; d->s2 = "1234"; ... d->~MyData(); free(v);

    正如 sharptooth 所指出的,如果没有初始化,您不能直接将 malloc 分配的内存用作 MyData 结构,因此您也必须自己做。要使用已分配的内存初始化 MyData,您需要使用placement new(参见上面的代码)。

    【讨论】:

    • 你也应该调用构造函数:::new (v) MyData; with using #include &lt;new&gt;
    • 但是MyData 是一个结构,不是一个类,它没有析构函数。
    • @Naszta:是的,谢谢,已经解决了这个问题。复制/粘贴确实容易出错。
    • @wormsparty: struct MyData {}; = class MyData { public: }; Struct 是一个类,默认继承是公共的而不是私有的。
    • @wormsparty:结构和类在 C++ 中是一样的(除了这里不相关的默认可见性),所以它们确实有构造函数和析构函数。
    【解决方案4】:

    是的,因为没有调用构造函数和析构函数。使用newdelete

    【讨论】:

    • 字符串的构造函数被调用,因为它们都被分配了。
    • @wormsparty 不,他们不是。 malloc 只是分配内存,没有调用构造函数。这就是new 的用途。
    • @wormsparty:如果使用malloc,则不调用构造函数,因此不调用字符串类构造函数,因此结果未定义。
    【解决方案5】:

    即使您设法正确初始化 s1 和 s2,简单地执行 free(d) 也不会回收为 s1 和 s2 动态分配的任何内存。您应该真正通过 new 创建 *d 并通过 delete 销毁,这将确保正确销毁 s1 和 s2(以及初始化)。

    【讨论】:

      【解决方案6】:

      是的,您可能正在泄漏,并且您的字符串也没有正确构造。程序的行为是未定义的,这意味着一切都会出错。

      最接近你正在做的事情的有效方法是placement new。不过,最好使用一些通用的基类和适当的 C++ 多态性。

      如果可能的类型不相关,您可以使用Boost.AnyBoost.Variant

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-11-09
        • 1970-01-01
        • 2021-01-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-26
        相关资源
        最近更新 更多