为什么移动构造函数和移动赋值运算符被调用而不是复制

why are move constructor and move assignment operator called and not copy?

本文关键字:移动 复制 调用 构造函数 赋值运算符 为什么      更新时间:2023-10-16

可能的重复项:
防止非常量左值解析为右值引用而不是常量左值引用
复制构造函数和转发构造函数之间的冲突

我有这些类,我需要存储 std::unique_ptr(适应的 boost::any):

class any
{
public:
  any()
    : content(0)
  {
  }
  any(any const&) = delete;
  any(any && other)
    : content(other.content)
  {
    content = 0;
  }
  template<typename ValueType>
  any(ValueType const& value)
    : content(new holder<ValueType>(value))
  {
  }
  template<typename ValueType>
  any(ValueType && value,
    typename std::enable_if<!std::is_lvalue_reference<ValueType>::value,
    void>::type* = 0)
    : content(new holder<ValueType>(std::move(value)))
  {
  }
  ~any()
  {
    delete content;
  }
public: // modifiers
  any & swap(any & rhs)
  {
    std::swap(content, rhs.content);
    return *this;
  }
  any & operator=(const any &) = delete;
  any & operator=(any && rhs)
  {
    return swap(rhs);
  }
  template<typename ValueType>
  any & operator=(ValueType const& rhs)
  {
    any(rhs).swap(*this);
    return *this;
  }
  template<typename ValueType>
  typename std::enable_if<!std::is_lvalue_reference<ValueType>::value,
    any&>::type operator=(ValueType && rhs)
  {
    any(std::move(rhs)).swap(*this);
    return *this;
  }
public: // queries
  bool empty() const
  {
    return !content;
  }
  const std::type_info & type() const
  {
    return content ? content->type() : typeid(void);
  }
private: // types
  class placeholder
  {
  public: // structors
  virtual ~placeholder()
  {
  }
  public: // queries
    virtual const std::type_info & type() const = 0;
  };
  template<typename ValueType>
  class holder : public placeholder
  {
  public: // structors
    template <class T>
    holder(T && value)
      : held(std::forward<T>(value))
    {
    }
    holder & operator=(const holder &) = delete;
  public: // queries
    virtual const std::type_info & type() const
    {
      return typeid(ValueType);
    }
  public:
    ValueType held;
  };
private: // representation
  template<typename ValueType>
  friend ValueType * any_cast(any *);
  template<typename ValueType>
  friend ValueType * unsafe_any_cast(any *);
  placeholder * content;
};

而这个测试用例:

any a;
any b(a);
b = a;

而这个:

std::map<int, int> map({{1,1},{2,2}});
any b(map);
std::cout << map.size() << std::endl; // displays 0

令我惊恐的是,在 gdb 下,我注意到在构造和分配b(甚至从 map)时调用移动构造函数和移动赋值运算符,即使我没有用 std::move 标记a,它也不是临时的。有人可以解释为什么吗?

我的第一个答案是错误的。再次阅读您非常难以阅读的代码后,我看到您明确提供了一个移动和默认构造函数,但没有复制构造函数。如果类具有任何用户定义的构造函数(其中有两个),则编译器不会为该类生成任何其他构造函数。因此,您的类没有复制构造函数

编辑:所以,回到我原来的答案(由您的评论提示)。 §12.8/7 [类复制] 说:

成员函数模板永远不会实例化以执行复制 类对象到其类类型的对象。 [示例:

struct S { 
    template<typename T> S(T); 
    template<typename T> S(T&&);
    S(); 
}; 
S f(); 
const S g; 
void h() { 
    S a( f() );          // does not instantiate member template; 
                         // uses the implicitly generated move
    constructor S a(g);  // does not instantiate the member template; 
                         // uses the implicitly generated copy constructor
}

—结束示例 ]

由于您的复制构造器是成员模板,但您的移动构造函数不是,因此在此处选择后者(您的情况与该方面的示例不同)。