Оператор присвоения C ++ для класса, который содержит уникальную переменную-член - PullRequest
1 голос
/ 18 апреля 2019

Я понимаю, что если у меня есть класс с умным уникальным указателем, невозможно присвоить этот класс другому экземпляру, так как уникальный указатель не может быть скопирован.Я понимаю, что могу сделать уникальный указатель общим указателем, и это решит проблему.Но что, если я не хочу делиться владением указателем?Можно ли создать оператор присваивания, который перемещает уникальный указатель и копирует другие переменные?

Я прочитал, что вы можете использовать std::move для передачи права собственности.

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

Ответы [ 2 ]

5 голосов
/ 18 апреля 2019

Конструктор по умолчанию класса test удален из-за невозможности копирования (graph_) члена (если вы все еще можете копировать любым осмысленным способом, например, путем создания глубокая копия члена графа, которую вы должны реализовать в своем собственном конструкторе копирования).Напротив, конструктор move по умолчанию все еще существует (std::unique_ptr является подвижным).Итак, что вы можете сделать, это следующее:

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

Имейте в виду, что t1, тогда не будет больше удерживать какой-либо объект (вы переместил объект, поэтому вы переместили его содержимое в другой объект), и объект, ранее удерживаемый t2, был уничтожен.Если это значимое состояние, решать вам ...

Примечание: то, что я написал о конструкторах копирования и перемещения, применимо и к назначению копирования и перемещения ...

3 голосов
/ 18 апреля 2019

Это легко исправить

Если GraphStructure является классом или структурой без каких-либо виртуальных функций-членов, это легко сделать. Мы можем написать функцию для дублирования данных внутри unique_ptr для создания нового GraphStructure:

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

Получив duplicate, мы можем использовать этот класс для написания конструктора копирования для теста:

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

Что если в GraphStructure есть виртуальные методы?

В этом случае добавьте виртуальный метод clone в GraphStructure, который возвращает новый 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() {}
};

Затем используйте .clone() вместо duplicate

...