C++ 使用运算符重载构建双面树 - 什么是好的内存解决方案?

标签 c++ pointers memory memory-management

所以按照我之前问的这个问题:C++ return by value - what happens with the pointer inside? 我想知道我是否进一步强加 parent 必须有一个指向他们 child 的指针列表,是否有任何好的解决方案,因为我将需要动态地在运算符体内分配内存。您可以假设计算图是非循环的。

具体考虑my.h:

class Interface{
public:
    int myid();
    Interface(double in);
    ~Interface(){
            std::cout<<"Destroy "<<myid()<<std::endl;
     }
    friend Interface operator+(const Interface& a, const Interface& b);
    void tree();
private:
    class Impl;
    std::shared_ptr<Impl> pimpl;
};
Interface operator+(const Interface& a, const Interface& b);

还有 my.cpp:

class autodiff::Interface::Impl{
public:
    static int id;
    int myid;
    double value;
    std::vector<std::shared_ptr<autodiff::Interface::Impl>> children;
    std::vector<std::weak_ptr<autodiff::Interface::Impl>> parents;
    Impl(double val) : value(val), myid(++id){};
    ~Impl(){
        std::cout<<"Destroy: "<<myid<<std::endl;
        for(auto it:children)
            it.reset();
    }
    void tree();

};

autodiff::Interface::Interface(double in){
    pimpl = std::make_shared<Impl>(in);
}

int autodiff::Interface::myid() {
    return pimpl->myid;
}

autodiff::Interface& autodiff::operator+(const Interface &a, const Interface &b) {
    Interface* ch = new Interface(a.pimpl->value + b.pimpl->value);
    a.pimpl->children.push_back(ch->pimpl);
    b.pimpl->children.push_back(ch->pimpl);
    ch->pimpl->parents.push_back(a.pimpl);
    ch->pimpl->parents.push_back(b.pimpl);
    return *ch;
}
void autodiff::Interface::tree() {
    pimpl->tree();
}
void autodiff::Interface::Impl::tree() {
    std::cout<<myid<<"-(";
    for(int i=0;i<parents.size();i++)
        if(auto tmp = parents[i].lock())
            std::cout<<tmp->myid<<",";
    std::cout<<")"<<std::endl;
    for(int i=0;i<parents.size();i++)
        if(auto tmp = parents[i].lock())
            tmp->tree();
}

int autodiff::Interface::Impl::id = 0;

输出是:

5-(4,3,)
4-(1,2,)
1-()
2-()
3-()
Destroy: 3
Destroy: 2
Destroy: 1

我想要和期望的是:

5-(4,3,)
4-(1,2,)
1-()
2-()
3-()
Destroy 3
Destroy 2
Destroy 1
Destroy 5
Destroy 4

我的问题是为什么临时创建的对象 4 和 5 没有自动释放?在 1、2、3 被销毁后,这些实例可能只有 weak_ptr 而没有 shared_ptr 还是我错了?

最佳答案

我没有读你之前的问题,但是当我曾经写一个二叉树实现时,我发现使用 std::unique_ptr 到子节点和一个简单的观察原始指针很方便到父节点,即类似于

struct Node
{
    Node *parent;
    std::unique_ptr<Node> right;
    std::unique_ptr<Node> left;
};

所有这些都应该初始化为std::nullptr。有了这个,leftright 下面的整个子树在 Node 被销毁后被正确销毁,所以没有必要递归地这样做。指向父节点的“观察指针”意味着您永远不应该对它执行一些与内存相关的操作,尤其是不要删除。

关于C++ 使用运算符重载构建双面树 - 什么是好的内存解决方案?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29197252/

相关文章:

c++ - 如何在 C++ 中获取数据段大小

c++ - C++中的切换栈

c - 如何将多维数组作为指针传递?

c++ - 为什么在 visual studio 2013/2015 上出现 vsnprintf 崩溃?

c++ - 动态内存分配 C++

c++ - Qt 5 : emit signal from non-Qt thread

c - 如何在 C 中为以下代码调试段错误。我在许多函数以及 main 中使用了 malloc 和 free

c++ - std::array<char, size> null 是否终止?

c++ - boost::interprocess 和valgrind

c++ - 如何将编译器标志仅限制到(我的)本地库?