【问题标题】:object containing smart pointer to itself that isn't reset before object goes out of scope包含指向自身的智能指针的对象,在对象超出范围之前不会重置
【发布时间】:2019-04-11 18:20:58
【问题描述】:

遇到了这个错误,其中一个类包含一个指向自身的指针——并且它指向同一个实例。这是包含该问题的最小代码sn-p...

class Node
{
public:
    Node()
    {
        std::cout << "constructor" << std::endl;
    }

    ~Node()
    {
        std::cout << "destructor" << std::endl;
    }

    void storeChild(boost::shared_ptr<Node> ptr)
    {
        m_ptr = ptr;
    }

private: 
    boost::shared_ptr<Node> m_ptr;
};

int main()
{
    boost::shared_ptr<Node> bc_ptr(new Node());
    bc_ptr->storeChild(bc_ptr); // this line is the bug 
    return 0;
}

我的问题是: 1. Node 对象是否曾经被删除过?我知道智能指针应该管理这些东西,所以我们不必删除。但看起来使用storeChild 传递给类的引用从未被重置。这是否意味着我将有内存泄漏? 2. 有没有办法使用智能指针来防止这种情况发生?显然,storeChild 方法应该被赋予一个指向不同节点的指针,但你如何防止这种情况发生?

如果我运行这个程序,析构函数永远不会被调用。

【问题讨论】:

  • Node 对象永远不会被删除,因为它拥有自己。我将首先在您的 storeChild 方法中添加 assert(this != ptr.get())。这是程序员的错误,你无法真正阻止它的发生。附带说明,如果您希望节点实际拥有其子节点,请考虑使用 unique_ptr。
  • boost::shared_ptr 现在有一个名为 std::shared_ptr 的标准类似物。

标签: c++ pointers shared-ptr


【解决方案1】:

是的,这是内存泄漏,因为Node 中的共享指针永远不会被删除。考虑:

#include <iostream>
#include <memory>

class Node {
    std::shared_ptr<Node> m_ptr;

public:
    Node() { std::cout << "constructor\n"; }
    ~Node() { std::cout << "destructor\n"; }
    void storeChild(std::shared_ptr<Node> ptr) { m_ptr = ptr; }
    long use_count() { return m_ptr.use_count(); }
};

int main() {   
    Node* n = new Node;
    {
        std::shared_ptr<Node> bc_ptr(n);
        bc_ptr->storeChild(bc_ptr); // this line is the bug

        std::cout << n->use_count() << "\n";     // prints 2
    }
    std::cout << n->use_count() << "\n";         // prints 1

    // the Node pointed to by n is leaked
}

如果你这样做可能会更明显:

#include <iostream>
#include <memory>

class Node {
    std::shared_ptr<Node> m_ptr;

public:
    Node() : m_ptr(this) { std::cout << "constructor\n"; }
    ~Node() { std::cout << "destructor\n"; }
};

int main() {
    new Node;
}

如果你尝试:

int main() {
    delete new Node;
}

Node 析构函数将被调用两次。首先是你的delete,其次是shared_ptr,当它被删除时。

如果有可能以循环所有权结束,例如:A->B->C->A ...如果有风险,您可能应该使用std::weak_ptr

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-02
    • 1970-01-01
    • 2013-10-01
    • 2021-05-18
    • 1970-01-01
    • 2016-09-25
    • 1970-01-01
    • 2020-01-03
    相关资源
    最近更新 更多