【问题标题】:why are move constructor and move assignment operator called and not copy? [duplicate]为什么调用移动构造函数和移动赋值运算符而不是复制? [复制]
【发布时间】:2012-04-13 07:42:44
【问题描述】:

可能重复:
Preventing non-const lvalues from resolving to rvalue reference instead of const lvalue reference
Conflict between copy constructor and forwarding constructor

我有存储 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(甚至来自地图)时调用了移动构造函数和移动赋值运算符,即使我没有用 @987654328 标记 a @ 并且它不是临时的。谁能解释一下原因?

【问题讨论】:

  • 一些一致的缩进会很有帮助。
  • 我为后代编辑了 boost::any hack。

标签: c++ boost stl c++11


【解决方案1】:

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

编辑:那么,回到我原来的答案(由您的评论提示)。 §12.8/7 [class.copy] 说:

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

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
}

——结束示例]

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

【讨论】:

  • 未选择此构造函数,如我的编辑中所述。
  • 调用的是move模板构造函数,不是anymove构造函数,还要检查map的构造,为什么会被移动?
  • 嗯,那我就不知道了。也许您可以提供一个最小的程序,以便我们可以在本地重现您的问题?
  • @user1095108:如果你需要帮助,你必须在你的问题上做一些工作。这包括提供一个程序,我可以复制/粘贴然后编译和执行以重现您的问题。另外,您使用的是哪个编译器和 boost-version?
  • 正确答案是˙T&&˙ 是模板函数中的一个包罗万象的参数,显然也是构造函数。解决方案见stackoverflow.com/questions/7748104/…
猜你喜欢
  • 1970-01-01
  • 2019-09-29
  • 2015-06-10
  • 1970-01-01
  • 2013-04-25
  • 1970-01-01
  • 1970-01-01
  • 2017-01-16
相关资源
最近更新 更多