c++ - 为什么这个 union 结构会导致内存泄漏?

标签 c++ pointers memory memory-leaks unions

我定义了一个 union 结构,它可以在字符串指针或长整数之间切换(这是由于对齐问题)。结构本身如下所示。

enum {H_STRING, H_LONG};
union Tag
{
    std::string *path;
    long id;
};

struct TextureID
{
    Tag tag;
    int type=H_STRING;

    TextureID()
    {
        type = H_STRING;
        tag.path = new std::string("");
    }
    TextureID(const TextureID& TID)
    {
        type = TID.type;
        if(type==H_STRING)
            tag.path = new std::string(*(TID.tag.path));
        else
            tag.id = TID.tag.id;
    }
    ~TextureID()
    {
        delete(tag.path);

    }

    TextureID& operator= (std::string str)
    {delete(tag.path); tag.path = new std::string(str); type=H_STRING; return *this;}
    TextureID& operator= (long val)
    { if(type==H_STRING) delete(tag.path); tag.id = val; type=H_LONG; return *this;}

    operator std::string&()
    {
        if(type == H_STRING)
        {
            return *(tag.path);
        }
    }
};

std::istream inline &operator>> (std::istream& is, TextureID& TID)
{is >> *(TID.tag.path); TID.type = H_STRING; return is;}

std::ostream inline &operator<< (std::ostream& os, TextureID& TID)
{return os << *(TID.tag.path);}

我使用 valgrind 确定这个数据结构存在内存泄漏。

验证此结构是内存泄漏原因的方法(即我确定这是原因而不是其他原因的原因)是重载当前正在使用的所有运算符(=、<<、>> ) 并且有两个版本的数据结构。第一个是您在上面看到的使用 union 的那个。第二个只是在 TextureID 中有一个字符串和一个 long 作为 2 个单独的字段。

第二种实现(不使用指针的实现)没有内存泄漏。

我知道如果标签设置为长,这可能会导致段错误。这不是问题,问题是不知何故,尽管有对 delete() 的显式调用,但分配的内存没有被删除(目前程序中没有任何内容将标记值设置为 long,因此也不会发生段错误)。

编辑:

有人要求我提供内存泄漏的证据,所以这里是:

enter image description here

此版本不会导致内存泄漏:

enum {H_STRING, H_LONG};

struct TextureID
{
    std::string path;
    long ID;
    int type=H_STRING;

    TextureID& operator= (std::string str)
    {path = str;}
    TextureID& operator= (long val)
    {ID = val;}

    operator std::string&()
    {
        if(type == H_STRING)
        {
            return (path);
        }
    }
};

std::istream inline &operator>> (std::istream& is, TextureID& TID)
{is >> TID.path; return is;}

std::ostream inline &operator<< (std::ostream& os, TextureID& TID)
{return os << TID.path;}

最佳答案

您的第一个代码示例中的问题几乎肯定在

TextureID& operator= (std::string str)
{delete(tag.path); tag.path = new std::string(str); type=H_STRING; return *this;}

这假设 tag.path 可以被删除。如果不是这样,它将导致未定义的行为 - 例如,如果 type == H_LONG

虽然这是否真的会导致泄漏值得商榷,但未定义行为的症状可以是任何东西,包括来自 valgrind 等工具的内存泄漏的虚假报告。

无论如何,一个简单的修复方法是更改​​此运算符以在执行 delete tag.path 之前检查 if(type == H_STRING)

第二个示例不会导致泄漏,因为 struct 单独包含成员,默认情况下,编译器将确保析构函数正确清理所有成员(调用析构函数等)。

正如 PaulMcKenzie 在评论中指出的那样,第二个示例还有其他问题,这些问题也可能导致未定义的行为(尽管在实践中可能不是内存泄漏)。我将不理会这些问题 - 这超出了所提出的问题。

关于c++ - 为什么这个 union 结构会导致内存泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51335807/

相关文章:

c++ - C/C++ 宏中的逗号

c - 在 rust 函数中没有* char(c_char)的问题,并显示一条消息没有帮助

c++ - 如何将派生对象添加到 unique_ptr 的 vector 中

c++ - 代码内联工作,但在类里面

c++ - String 类的隐式构造函数

c++ - 查看 STL 容器中的下一个元素

c++ - 指针递增和递减

ios - 仅由于内存错误,iOS8 上的应用程序崩溃

linux - 使用hexdump检查/dev/mem时,为什么有些地址不见了?

c++ - 在 Arduinos 上,函数内的变量是否始终保留在 RAM 中?