如何安全删除新分配的结构?

时间:2019-05-11 13:40:22

标签: c++ valgrind destructor

我正在尝试创建一些复杂的数据结构,这是一个简单的演示:

#include <iostream>
#include <vector>

struct Item;
struct Store;

struct globalEnviroment
{
     Item * data;
     globalEnviroment(Item * paramData) : data(paramData){}            
     ~globalEnviroment()
     {
        delete data;
     }
};

struct Item
{
        int id;
        std::vector<std::string>* names;

        Item() {};
        ~Item ( ) {delete names;}
};

int main ( )
{
    Item * items = new Item[3];
    items[0].names = new std::vector<std::string>();
    items[1].names = new std::vector<std::string>();
    items[2].names = new std::vector<std::string>();
    globalEnviroment * ge = new globalEnviroment(items);

    delete ge;

    return 0;
}

我要

  

munmap_chunk():无效的指针

delete data;行出错。

我不确定删除globalEnviroment类型的对象的正确方法是什么。我的析构函数工作正常吗?

1 个答案:

答案 0 :(得分:1)

globalEnviroment

的析构函数中有两个问题
  • Item 的定义是未知的,编译时没有警告?
  • delete data;必须为delete [] data;(在当前情况下,您创建的实例给i参数一个new Items[...]的结果,而不是new Item的结果)

第一种可能性是将 Item 的定义移到 globalEnviroment 的定义之前,同时更正删除操作:

#include <vector>
#include <string>

struct Item
{
        int id;
        std::vector<std::string>* names;

        Item() {};
        ~Item ( ) {delete names;}
};

struct globalEnviroment
{
     Item * data;
     globalEnviroment(Item * paramData) : data(paramData){}            
     ~globalEnviroment()
     {
        delete [] data;
     }
};

int main ( )
{
    Item * items = new Item[3];
    items[0].names = new std::vector<std::string>();
    items[1].names = new std::vector<std::string>();
    items[2].names = new std::vector<std::string>();
    globalEnviroment * ge = new globalEnviroment(items);

    delete ge;

    return 0;
}

编译和执行:

pi@raspberrypi:/tmp $ g++ -pedantic -Wall -Wextra c.cc
pi@raspberrypi:/tmp $ ./a.out

valgrind 下执行:

pi@raspberrypi:/tmp $ valgrind ./a.out
==13369== Memcheck, a memory error detector
==13369== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==13369== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==13369== Command: ./a.out
==13369== 
==13369== 
==13369== HEAP SUMMARY:
==13369==     in use at exit: 0 bytes in 0 blocks
==13369==   total heap usage: 6 allocs, 6 frees, 20,296 bytes allocated
==13369== 
==13369== All heap blocks were freed -- no leaks are possible
==13369== 
==13369== For counts of detected and suppressed errors, rerun with: -v
==13369== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)

第二种可能性是将析构函数的定义移到 Item 的定义之后:

#include <vector>
#include <string>

struct Item;

struct globalEnviroment
{
     Item * data;
     globalEnviroment(Item * paramData) : data(paramData){}            
     ~globalEnviroment();
};

struct Item
{
        int id;
        std::vector<std::string>* names;

        Item() {};
        ~Item ( ) {delete names;}
};

globalEnviroment::~globalEnviroment()
{
  delete [] data;
}

int main ( )
{
    Item * items = new Item[3];
    items[0].names = new std::vector<std::string>();
    items[1].names = new std::vector<std::string>();
    items[2].names = new std::vector<std::string>();
    globalEnviroment * ge = new globalEnviroment(items);

    delete ge;

    return 0;
}

编译和执行的结果相同


除此之外

  • 您的类中有一个指针,您必须负责分配,复制构造函数等,您必须定义它们。
  • Item 的构造函数不会将 names 初始化为NULL,如果在析构函数将具有未定义的行为之后未设置该字段,则为
  • 如果使用 Items 数组或仅使用 Item 进行初始化,则必须假设 data ,但是无论您调用什么代码,都可以完美地编译其构造函数的参数为​​newItemnew Item[..]

如果您想使用指针进行练习,请不要一开始就停下来,走得更远;-)