I rummaged through SO and learned a lot regarding default constructors, copy constructors, objects assignment, smart pointers, shallow/deep copy and their relationships with dynamic memory allocation (e.g. This, This, That and ...). However, I'm still fuzzy on drawing a conclusion on what the best practice is to handle copying objects elements such as vectors (or list).
I learnt STL vector, in particular, handles this by its default copy constructor and best practice in this case is to not manage resources yourself. But it seems I'm understanding something wrong.
My effort before asking: I was also able to resolve this with passing the objects by reference but I ended of having too many deference operators (i.e. **).
What's the best practice here for simple small objects such as the one in the following code? Elements in vectors are not being copied properly. (I'd not be surprised if I'm doing extremely simple mistake here. Also, not using raw/shared/smart pointers is preferred if possible).
#include <iostream>
#include <vector>
using namespace std;
class A{
public:
int id;
A(int id_):id(id_){}
vector<A> childs;
};
int main()
{
A a0(0), a1(1);
a0.childs={a1}; //node0.childs.push_back(node1);
a1.childs={a0}; //node1.childs.push_back(node0);
cout << a0.childs.size() << endl; // 1
cout << a1.childs.size() << endl; // 1
cout << a0.childs[0].childs.size() << endl; // expecting 1 but 0
//Probably since they're not pointing to the same address of memory
//I was hoping vector handle this by itself (was told best practice in this case is to not manage resources yourself)
return 0;
}
I think I understand what you are trying to achieve but if the objective is learning, then I strongly recommend you understand why, what you are expecting to happen, isn't happening. Before you move on to finding a "workaround" to achieve what you are trying to achieve.
To better understand, it might help to write simplified code that demonstrates the same behavior. What you have written is more-or-less equivalent to:
which is equivalent to:
which is equivalent to:
a0holds a separate copy ofa1not a reference toa1so if you make a change to the originala1, the copy ofa1held ina0does not change.EDIT: As for how to achieve what you want to achieve. I'm assuming that
Ashould not own its children. You want it to contain non-owning references to theAs that are held elsewhere. Unfortunately, astd::vectorcannot hold a C++ reference. Thestd::vectorcould hold a raw pointer but you specifically asked to not use raw pointers.An alternative, is a
std::reference_wrapper<A>which is something that behaves a bit like a C++ reference but is assignable so that it can be used in astd::vector. You could hide thestd::reference_wrapperby providing a member function to get access to a child by index:Live demo.
But to be clear,
std::reference_wrapperis basically just a wrapper around a raw pointer, it is up to you to ensure that object it is pointing to is still alive.Edit2: As requested, here is a version that uses a vector of raw pointers:
Live demo.
Note that you have to take the address of
a1using&when initializing the vector.