#include <memory>
#include <algorithm>

using namespace std;

class A {
public:
    unique_ptr<int> u;
    A(){}
    A(const A& other): u(new int(*other.u)){} // If I comment this out, it works.
    // A(A&&){} // This does not help.
};

int main() {
    A a;
    A b = a;
    swap(a, b);
}

Этот код не работает - вылетает из-за стены ошибок шаблона, говорящей no matching function for call to ‘swap(A&, A&)’. Почему? Удаление второго конструктора помогает, но мне он нужен в другом коде. Я догадывался, что это может быть связано с автоматическим удалением некоторых конструкторов, когда определены другие, но добавление конструктора перемещения вручную тоже не помогает. Как я могу это исправить?

0
akrasuski1 13 Янв 2018 в 20:06

1 ответ

Лучший ответ

std::swap() требует, чтобы его аргументы были конструируемым перемещением и назначаемым перемещением .

Данный:

struct A {
    unique_ptr<int> u;
    A();
};

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

Но, учитывая:

struct A {
    unique_ptr<int> u;
    A();
    A(A const&);
};

Объявляя определяемый пользователем конструктор копирования, вы запрещаете неявное определение конструктора перемещения A и оператора присваивания перемещения (и, имея член, который нельзя присваивать и копировать, вы запрещаете неявную генерацию конструктора копирования и оператора присваивания копии A).

Чтобы снова сделать A заменяемым, вам нужно либо определить пользователем both (*):

struct A {
    unique_ptr<int> u;
    A();
    A(A const&);
    A(A&&);
    A& operator=(A&&);
};

Или ни то, ни другое, и просто добавьте правильное копирование:

struct A {
    unique_ptr<int> u;
    A();
    A(A const&);
    A& operator=(A const&);
};

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


(*) noexcept спецификации опущены для краткости ...

5
Massimiliano Janes 14 Янв 2018 в 08:42