简体   繁体   中英

class with unique_ptr of vector to class

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;
}

The idea of unique_ptr is to manage an object on the heap, ie 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]) {}
};

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. (*)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM