Что приводит к тому, что оператор присваивания перемещения не вызывается? - PullRequest
0 голосов
/ 17 ноября 2018

Я работаю над собственным умным указателем и столкнулся с некоторыми странными проблемами.Оператор назначения перемещения не вызывался.Поэтому я написал тестовый класс и смог воспроизвести проблему.Оператор назначения перемещения не вызывается, но происходит назначение копирования (даже когда нет оператора назначения копирования).

Это мой тестовый класс

#include <utility>
#include <iostream>

struct tag_t {};
constexpr tag_t tag {};

template <typename T>
struct Foo {
  Foo() noexcept
    : val{} {
    std::cout << "Default construct\n";
  }
  template <typename U>
  Foo(tag_t, const U &val) noexcept
    : val{val} {
    std::cout << "Construct " << val << '\n';
  }
  ~Foo() noexcept {
    std::cout << "Destruct " << val << '\n';
  }

  template <typename U>
  Foo(Foo<U> &&other) noexcept
    : val{std::exchange(other.val, U{})} {
    std::cout << "Move construct " << val << '\n';
  }
  template <typename U>
  Foo &operator=(Foo<U> &&other) noexcept {
    std::cout << "Move assign " << other.val << '\n';
    val = std::exchange(other.val, U{});
    return *this;
  }

  T val;
};

Это тесты

int main() {
  {
    Foo<int> num;
    std::cout << "Value " << num.val << '\n';
    num = {tag, 5};
    std::cout << "Value " << num.val << '\n';
  }
  std::cout << '\n';
  {
    Foo<int> num;
    std::cout << "Value " << num.val << '\n';
    num = Foo<int>{tag, 5};
    std::cout << "Value " << num.val << '\n';
  }
  return 0;
}

После запуска тестов я получаю эти результаты

Default construct
Value 0
Construct 5
Destruct 5
Value 5
Destruct 5

Default construct
Value 0
Construct 5
Move assign 5
Destruct 0
Value 5
Destruct 5

Меня сбивает с толку вывод первого теста.Оператор назначения перемещения не вызывается, но выполняется назначение копирования.В результате 5 уничтожается дважды.Не идеально, когда вы пытаетесь сделать умный указатель!

Я компилирую с Apple Clang с отключенной оптимизацией.Может кто-нибудь объяснить мои наблюдения?Кроме того, как я могу убедиться, что оператор присваивания был вызван в первом тесте?

1 Ответ

0 голосов
/ 17 ноября 2018
template <typename U>
Foo &operator=(Foo<U> &&other) noexcept;

это не может быть вызвано ={ }.

Вместо этого вызывается Foo& operator=(Foo&&)noexcept.

Методы шаблона никогда не являются специальными функциями-членами.Явно по умолчанию, удалить или реализовать их.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...