Конструктор и оператор присваивания в дереве
Я написал рабочий копирующий конструктор, оператор копирования, и деструктор для своего дерева, но не могу разобраться с конструктором и оператором присваивания. Пробовал разные варианты, но каждый раз получаю одни и те же ошибки. Также у меня есть рабочая функция swap. Дерево содержит корень и переменную с количеством слов. В чем может быть проблема?
tree::tree(tree &&rhs)
{
tree tmp(rhs);
swap(tmp);
tree * ptr = &tmp;
ptr->~tree();
}
tree &tree::operator=(tree &&rhs) {
tree tmp(rhs);
swap(tmp);
tree * ptr = &tmp;
ptr->~tree();
return *this;
}
void tree::swap(tree &rhs)
{
std::swap(root, rhs.root);
std::swap(size, rhs.size);
}
Ответы (1 шт):
Во-первых, надо разобраться с терминами. Вы пишете "перемещающие" операции (перемещающий конструктор и перемещающий оператор присваивания). А версии с const tree &, которые у вас уже есть, это "копирующие" операции (копирующий конструктор и копирующий оператор присваивания).
Во-вторых, даже если убрать лишний вызов деструктора, это очень неудачная реализация, потому что вы копируете все дерево. А смысл перемещения как раз в избегании лишних копий. С тем же успехом можно просто не писать перемещающие операции, и компилятор будет сам использовать вместо них копирующие.
Самое минимальное исправление такое:
tree::tree(tree &&other) : root(other.root), size(other.size)
{
other.root = nullptr;
other.size = 0;
}
tree &tree::operator=(tree &&other)
{
tree tmp(std::move(other));
swap(*this, tmp); // Или убрать самодельный свап и здесь руками свапнуть поля.
return *this;
}
Но лучше так:
tree(tree &&other) noexcept
: root(std::exchange(other.root, {})), size(std::exchange(other.size, {}))
{}
tree &tree::operator=(tree other) noexcept
{
swap(*this, other);
return *this;
}
И убрать копирующее присваивание, потому что это (с параметром tree по значению) - универсальное, и работает и для копирования, и для присваивания.
std::exchange просто для красоты.
noexcept - потому что без него, если положить ваше дерево в стандартный контейнер вроде std::vector, он в некоторых ситуациях будет брезговать перемещением и вызывать копирование, чтобы избежать возможных исключений.