Что мне нужно для возврата объекта с уникальным членом? - PullRequest
0 голосов
/ 27 сентября 2018

Допустим, у меня есть этот объект:

struct foo {
    std::unique_ptr<int> mem;
    virtual ~foo() = default;
};

Я больше не могу вернуть foo объект, созданный в функции:

foo make_foo() {
    foo result;

    result.mem = std::make_unique<int>({});
    return result;
}

Как может быть указано, мне нужнодеструктор должен быть виртуальным, потому что это будет базовый класс.Но даже если я использую деструктор по умолчанию, этого недостаточно, я все равно не могу вернуть объект, созданный в функции.

Я получаю ошибку:

error C2280: foo::foo(const foo &): attempting to reference a deleted function

Есть лиспособ обойти эту проблему?

Ответы [ 2 ]

0 голосов
/ 27 сентября 2018

Либо предоставьте свой собственный конструктор копирования и конструктор по умолчанию, преобразуйте элемент в общий указатель или предоставьте конструктор перемещения.Одно из возможных решений:

struct foo {
    unique_ptr<int> mem;
    foo() = default;
    foo(const foo& copy);
    virtual ~foo() = default;
};

foo::foo(const foo& copy) : mem(new int(*copy.mem)) {}

foo make_foo() {
    foo result;
    result.mem = make_unique<int>();
    return result;
}
0 голосов
/ 27 сентября 2018

Per [class.copy.ctor] / 8

Если определение класса X явно не объявляет конструктор перемещения, неявный будетнеявно объявляется дефолтным, если и только если [...]

  • X не имеет объявленного пользователем деструктора.

С

virtual ~foo() = default;

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

Чтобы получитьпереместите конструктор назад, и чтобы сохранить конструкцию по умолчанию, вам нужно добавить

foo() = default;
foo(foo&&) = default;
foo &operator=(foo &&) = default; // add this if you want to move assign as well

к foo


Причина, по которой вы должны добавить foo() = default; при добавленииfoo(foo&&) = default; заключается в том, что foo(foo&&) = default; является конструктором, который используется и если у вас есть какие-либо конструкторы, объявленные пользователем, тогда конструктор по умолчанию больше не предоставляется.


Это "взлом", но выможно было бы переместить виртуальный деструктор в другой класс, а затем наследовать от него.Это даст вам виртуальный деструктор в foo без необходимости объявлять его и даст вам необходимые конструкторы по умолчанию.Это будет выглядеть как

struct make_virtual
{
    virtual ~make_virtual() = default;
};

struct foo : make_virtual {
    std::unique_ptr<int> mem;
};
...