So following this question I asked before: C++ return by value - what happens with the pointer inside? I was wondering if further I impose that the parents have to have a list of pointer to their children, is there any good solution, in terms of not having any memory leaks with shared and weak pointers in any way, since I will need to dynamically allocate memory inside the body of the operator. You can assume that the compute graph is acyclic.
Specifically consider 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);
And the 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;
The output is:
5-(4,3,)
4-(1,2,)
1-()
2-()
3-()
Destroy: 3
Destroy: 2
Destroy: 1
Where what I want and expect was:
5-(4,3,)
4-(1,2,)
1-()
2-()
3-()
Destroy 3
Destroy 2
Destroy 1
Destroy 5
Destroy 4
My question is why aren't the temporary created objects 4 and 5 get freed automatically? After 1,2,3 are destroyed there could be only weak_ptr to those instance and no shared_ptr or am I wrong?