代码之家  ›  专栏  ›  技术社区  ›  Indiana Kernick Michael Durrant

是什么导致不调用移动分配运算符?

  •  2
  • Indiana Kernick Michael Durrant  · 技术社区  · 7 年前

    我正在开发自己的智能指针,遇到了一些奇怪的问题。未调用移动分配运算符。因此,我编写了一个测试类,能够重现这个问题。不会调用移动分配运算符,但会发生复制分配(即使没有复制分配运算符)。

    这是我的测试课

    #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 两次被摧毁。当你试图制作一个智能指针时,这并不理想!

    1 回复  |  直到 7 年前
        1
  •  5
  •   Yakk - Adam Nevraumont    7 年前
    template <typename U>
    Foo &operator=(Foo<U> &&other) noexcept;
    

    这不能由 ={ } .

    相反 Foo& operator=(Foo&&)noexcept 被称为。