【问题标题】:How to delete new pointer that declared on function parameters?如何删除在函数参数上声明的新指针?
【发布时间】:2015-05-28 17:46:12
【问题描述】:

我的类有成员函数,它把它自己的类型的指针作为它的参数。

当我这样做时:

Object* obj1 = new Object();
Object* obj2 = new Object();

obj1->add_child(obj2)

delete obj1;
delete obj2;
obj1 = NULL;
obj2 = NULL;

然后运行valgrind,报告说:

HEAP SUMMARY:
    in use at exit: 72,704 bytes in 1 blocks
  total heap usage: 6 allocs, 5 frees, 73,098 bytes allocated

LEAK SUMMARY:
   definitely lost: 0 bytes in 0 blocks
   indirectly lost: 0 bytes in 0 blocks
     possibly lost: 0 bytes in 0 blocks
   still reachable: 72,704 bytes in 1 blocks
        suppressed: 0 bytes in 0 blocks

我读到an answerstill reachable 很好,没有泄漏。然后,当我尝试这个时:

Object* obj = new Object();

obj1->add_child(new Object());

delete obj;
obj = NULL;    

valgrind 的报告说:

HEAP SUMMARY:
    in use at exit: 72,877 bytes in 3 blocks
  total heap usage: 6 allocs, 3 frees, 73,098 bytes allocated

LEAK SUMMARY:
   definitely lost: 144 bytes in 1 blocks
   indirectly lost: 29 bytes in 1 blocks
     possibly lost: 0 bytes in 0 blocks
   still reachable: 72,704 bytes in 1 blocks
        suppressed: 0 bytes in 0 blocks

很明显,我没有删除作为参数传递的new Object() 指针。那么,如何删除那个指针呢?

详细更新

add_child(Object* obj)的定义:

void add_child(Object* obj) {

    container.add_child(obj);
}

containerObject 的成员,Object 是模板类的一个实例。

Container<Object> container;

Container 的定义是:

template<class T>
class Container {
public:
    void add_child(const std::string& key, T* child) {
        childrens.insert(std::pair<std::string,T*>(key, child));
    }
private:
    std::multimap<std::string,T*> childrens;
}

那么,childrens其实是std::multimap

我希望这只是一个问题。

【问题讨论】:

  • 指针存放在哪里?这就是你删除的内容。
  • 如果不知道Object 类的定义,就无法判断。不过,您确实应该使用智能指针(例如 unique_ptrshared_ptr)。
  • 请注意,它显示的是72,704 bytes in 1 blocks,它与第二个程序中丢失指针的大小不匹配。你知道在你的程序中什么可能是一个如此大的对象吗? (因为它说“1块”,它可能是一个数组,给定这么大的尺寸)
  • 已更新。这就是我存储指针的方式。
  • 你使用什么版本的 gcc? If it's 5.1, then you may suffer from this bug

标签: c++ pointers new-operator


【解决方案1】:

您需要对谁拥有指针做出明确且一致的选择。如果您决定 add_child 取得所有权, 那么调用者应该期望他们不需要删除传入的指针。如果您决定 add_child 不取得所有权, 然后调用者保留所有权并删除指针。

您可以让Object 取得所有权,因此它的析构函数会删除所有已添加到它的子指针。那么你的第一个例子应该是

Object* obj1 = new Object();
Object* obj2 = new Object();

obj1->add_child(obj2);

delete obj1; // also deletes obj2 automatically

你的第二个:

Object* obj = new Object();

obj->add_child(new Object());

delete obj; // automatically deletes the unnamed pointer passed in on previous line

如果您不希望 Object 获得所有权,那么您就有问题了,因为您无法在调用者的上下文中删除 new Object()

如果您使用智能指针,管理所有权会变得容易得多。 add_child 可以接受 std::unique_ptr&lt;Object&gt; 参数。

auto obj1 = std::make_unique<Object>();
auto obj2 = std::make_unique<Object>();
obj1->add_child(std::move(obj2)); // obj1 takes ownership
// both pointers automatically deleted at scope exit

auto obj = std::make_unique<Object>();
obj->add_child(std::make_unique<Object>());
// both pointers automatically deleted at scope exit

【讨论】:

    【解决方案2】:

    函数调用完成后,您将不再拥有new 创建的指针。如果你调用的函数没有删除指针,那么你有内存泄漏。

    【讨论】:

      【解决方案3】:

      关于您仍然可以访问的内存块的 valgrind 报告不是您的错 - it's the bug in gcc 5.1

      我是怎么想到这个的:

      块大小非常大(72704)并且与分配对象的大小不匹配,所以接下来我尝试将72704 除以14429 以查看它是否是这些的数组对象。

      但不是因为7270472704-472704-8(数组,数组 + 32 位整数存储大小,数组 + 64 位整数存储大小)都不是' t 可分。然后我用谷歌搜索了“72,704 still reachable”,它显示了提到的问题。

      其他回答者关于使用智能指针(如std::unique_ptrstd::shared_ptr)的建议是合理的,我也推荐使用它们。

      【讨论】:

        猜你喜欢
        • 2018-11-11
        • 1970-01-01
        • 2011-07-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-13
        • 1970-01-01
        相关资源
        最近更新 更多