简体   繁体   中英

C++ Assignment operator for class that contains a unique pointer member variable

I understand that if I have a class with a smart unique pointer, it is not possible to assign that class to another instance, as a unique pointer cannot be copied. I understand that I could make the unique pointer a shared pointer and this would solve the problem. But what if I did not want to share ownership of the pointer? Is it possible to create an assignment operator that moves the unique pointer and copies the other variables?

I have read that you can use std::move to pass ownership.

#include <iostream>
#include <memory> 

struct GraphStructure { };

class test {

        int a;
        std::vector<int> vector;
        std::unique_ptr<GraphStructure> Graph_; 
 };

 int main () {

     test t1;
     auto t2 = t1;
 }

The default copy constructor of class test is deleted because of a member ( graph_ ) not being copiable (if you still could copy in any meaningful way, eg by creating a deep copy of the graph member, you'd have to implement on your own copy constructor). In contrast, the default move constructor still exists ( std::unique_ptr is movable). So what you can do is the following:

test t1;
auto t2 = std::move(t1);

Be aware, though, that t1 then won't hold any object any more (you moved the object, so you moved its contents to another one) and the object previously held by t2 is destroyed. If this is a meaningful state is up to you to decide...

Side note: What I wrote about copy and move constructors applies for copy and move assignment as well...

Fixing this the easy way

If GraphStructure is a class or struct without any virtual member functions, this is easy to do. We can write a function to duplicate the data inside a unique_ptr to create a new GraphStructure :

std::unique_ptr<GraphStructure> duplicate(std::unique_ptr<GraphStructure> const& ptr)
{
    return std::make_unique<GraphStructure>(*ptr);
}

Once we have duplicate , we can use this class to write a copy constructor for test:

class test {
    std::unique_ptr<GraphStructure> ptr;
    std::vector<int> values;
   public:
    // this can be defaulted
    test() = default;
    // we use duplicate to create a copy constructor
    test(const test& source) 
      : ptr(duplicate(source.ptr)))
      , values(source.values)
    {}
    // we can use the default move constructor
    test(test&&) = default;

    test& operator=(test const& source) {
        ptr = duplicate(source.ptr);
        values = source.values; 
        return *this;
    }
    // we can use the default move assignment operator 
    test& operator=(test&&) = default;
};

What if GraphStructure has virtual methods?

In this case, add a virtual clone method to GraphStructure that returns a new std::unique_ptr<GraphStructure> :

class GraphStructure {
   public:
    // override this method in child classes
    virtual std::unique_ptr<GraphStructure> clone() {
        return std::make_unique<GraphStructure>(*this);
    }
    virtual ~GraphStructure() {}
};

Then, use .clone() in place of duplicate

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