Reputation: 59
How to implement a class containing a unique_ptr to a vector containing elements of the same class to build kind of a hierarchical structure.
I had implemented the same example using normal pointer before. That had worked fine.
Now I am trying to adapt to c++11 using unique_ptr.
The line marked with the "works" comment seems to do what I expect. The same kind of statement used inside the copy construct seems to fail copying the actual contents of the vector into the new instance.
I am using Visual Studio 2013.
Background information:
I have stripped down the class. The iPOD is only representing a lot of other members also existing within the class. The class is used as representation of single attributes of an HMI widget tree.
#include <string>
#include <memory>
#include <vector>
void func();
struct Attribute;
typedef std::vector<Attribute> AttributeVector;
struct Attribute
{
int m_iPOD;
//AttributeVector *m_kAttrVectorPtr; // Old version before unique_ptr did work...
std::unique_ptr<AttributeVector> m_kAttrVectorPtr; // New version using unique_ptr
/** Default constructor. */
Attribute()
: m_iPOD(-1), m_kAttrVectorPtr(nullptr)
{
}
/** Constructs an attribute. */
Attribute(int iPOD, std::unique_ptr<AttributeVector> kAttrs)
: m_iPOD(iPOD), m_kAttrVectorPtr(std::move(kAttrs))
{}
/** Copy constructor.
@param kSource Source instance.
*/
Attribute(const Attribute& kSource)
: m_iPOD(kSource.m_iPOD)
{
if(kSource.m_kAttrVectorPtr)
m_kAttrVectorPtr = std::unique_ptr<AttributeVector> (new AttributeVector(kSource.m_kAttrVectorPtr));
else
m_kAttrVectorPtr = nullptr;
}
/** Assignment operator.
@param kSource Source instance.
*/
Attribute& operator=(const Attribute& kSource)
{
m_iPOD = kSource.m_iPOD;
if(kSource.m_kAttrVectorPtr)
m_kAttrVectorPtr = std::unique_ptr<AttributeVector> (new AttributeVector(kSource.m_kAttrVectorPtr));
else
m_kAttrVectorPtr = nullptr;
return *this;
}
bool operator==(const Attribute& rkOther) const
{
return m_iPOD == rkOther.m_iPOD;
// Todo real compare m_kAttrVectorPtr == rkOther.m_kAttrVectorPtr;
}
bool operator!=(const Attribute& rkOther) const
{
return !operator==(rkOther);
}
};
int main()
{
AttributeVector kVector;
Attribute kAttr1;
kAttr1.m_iPOD = 101;
kAttr1.m_kAttrVectorPtr = nullptr;
Attribute kAttr2;
kAttr2.m_iPOD=102;
kAttr2.m_kAttrVectorPtr = nullptr;
kVector.push_back(kAttr1);
kVector.push_back(kAttr2);
Attribute kAttr;
kAttr.m_iPOD=100;
kAttr.m_kAttrVectorPtr = std::unique_ptr<AttributeVector> (new AttributeVector(kVector)); // Works result= kattr with a vector of 2 attributes
Attribute kAttrCopy(kAttr);// does not work. Only one entry within m_kAttrVectorPtr after copy instead of the 2 from above
Attribute kAttrAssign;
kAttrAssign = kAttr;// does not work. Only one entry within m_kAttrVectorPtr after copy instead of the 2 from above
return 0;
}
Upvotes: 0
Views: 1241
Reputation: 45414
The idea of unique_ptr
is to manage an object on the heap, i.e. to automatically delete
it once the pointer goes out of scope. A vector
does the same with its contents, so allocating a vector
on the heap is just a waste of resources (time and memory). This means that already your previous design which allocated a vector
was flawed. Instead of
struct A {
vector<A> *pvec;
A() : pvec(new vector<A>) {}
~A() { delete pvec; }
};
(which you are attempting to improve with unique_ptr
), simply use
struct A {
vector<A> vec; // requires 24 bytes on 64bit machines
// auto generated constructor and destructor
};
Alternatively, if the number of objects hold in the vector
are known at the start, you could use a unique_ptr
:
struct A {
unique_ptr<A[]> vec; // requires 8 bytes on 64bit machines
A(size_t n)
: vec(new A[n]) {}
};
Upvotes: 4
Reputation: 1211
Replace new AttributeVector(kSource.m_kAttrVectorPtr)
with new AttributeVector(*kSource.m_kAttrVectorPtr)
.
You can't construct a vector with any pointer, but with the value itself. (*)
Upvotes: 0