C++构建一个带有运算符重载的双边树-什么是好的内存解决方案
C++ building a double sided Tree with operator overloading - what is good memory solution?
下面是我之前问的这个问题:C++按值返回-指针在里面会发生什么?我想知道,如果我进一步规定父母必须有一个指向他们孩子的指针列表,有没有什么好的解决方案,在任何方式下都不会有任何共享和弱指针的内存泄漏,因为我需要在运算符的内部动态分配内存。您可以假设计算图是非循环的。
具体考虑我的.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
。这样,一旦Node
被破坏,left
或right
下面的整个子树就会被正确地破坏,因此不需要递归地这样做。指向父节点的"观察指针"意味着永远不应该对它执行一些与内存相关的操作,尤其是不删除。
相关文章:
- 运行同一解决方案的另一个项目的项目
- Project Euler问题4的错误解决方案
- 计算每个节点的树高,帮助我解释这个代码解决方案
- C++:Application.cpp中抛出了未解析的外部符号(解决方案在问题的末尾,供未来的读者参考)
- visual c++,如何获取解决方案目录中的代码
- 有没有办法在远程设备上打开和编辑visual Studio 2017解决方案
- C++Matching Brackets 2解决方案不起作用
- 在 ubuntu3 上C++ goto 定义有什么解决方案吗16.04?
- 在 leetcode 上提交解决方案时出现堆栈缓冲区溢出错误
- 我的固定时间步长与增量时间和插值的解决方案是错误的吗?
- 无法在问题解决方案中执行输出逻辑
- 最大的回文产品 - 程序未运行,编写解决方案但无法理解问题
- 从预序遍历构造 bst 的 c++ 和 python 解决方案之间的区别
- 在一个解决方案中针对第三方静态库 (Creo) 的不同版本(版本)进行构建
- 如何巧妙地编写两个函数——一个用于检查是否存在解决方案,另一个用于获取所有解决方案
- C++构建一个带有运算符重载的双边树-什么是好的内存解决方案
- 用C++替换内存管理器的单例解决方案
- 查找内存泄漏的最佳解决方案
- MPI错误:内存不足-有哪些解决方案选项
- 正在寻找C++中基于Windows RAM的共享内存解决方案