【问题标题】:Function dual to std::move?与 std::move 对偶的功能?
【发布时间】:2013-07-05 22:50:40
【问题描述】:

假设我有一个只有一个构造函数的类:

class T {
 public:
  T(BigClass&& big) : big(std::move(big)) {}
  ...

  SomeBigClass
};

在大多数情况下,构造函数是在临时对象上调用的,但在一个地方我需要创建 BigClass 的显式副本,因为它不是临时对象,并且会在循环中多次使用:

void foo(const BigClass& big) {
  while (...) {
    T t(std::make_a_copy(big));
    ...
  }
}

在 C++11 或 C++14 中是否有任何与 std::move“对偶”的函数可以替换上面的 make_a_copy ?

编辑:一些说明。

【问题讨论】:

  • 如果您可能需要进行复制,那么您不应该也提供一个T(BigClass const & big) 构造函数然后调用它吗?
  • 为什么需要复制一个临时的,而不是一个move?这似乎有点荒谬。
  • 有人可能会拒绝我的编辑。
  • 如果你想写尽可能少的函数,两个“核心”是复制构造函数和swap。移动构造函数、复制赋值和移动赋值可以写成复制构造函数和交换。没有复制构造函数……没有捷径。
  • 这个问题与标题所说的完全无关。在你有一个右值引用表达式并且你需要一个 modifiable 左值引用(如果你这样写它不会绑定,并创建右值的临时值也不起作用,因为它只能初始化 const 左值引用)。情况并非如此,您的情况正好相反;可以使用std::move 进行编译,但这并不符合您的要求。解决方法是先复制big的值,和你的class T无关。

标签: c++ c++11 move-semantics


【解决方案1】:

为什么不能只复制BigClass 对象?

void foo(const BigClass& big) {
  while (...) {
    T t{ BigClass(big) };
    ...
  }
}

这会生成一个临时的BigClass,然后将其移动到T

【讨论】:

  • 看起来它甚至不需要显式副本。
  • @Xeo:是的,它确实需要显式副本;问题明确指出Tunique 构造函数采用BigClass&&,特别是没有构造函数T::T(const BigClass&) 的使用会为您创建和绑定临时对象。
【解决方案2】:

不难写:

template <typename T>
T make_temp(const T& x) { return x; }

可能有一个标准函数在使用一个参数调用时碰巧做到了这一点,但没有针对这种不寻常模式设计的标准函数。

【讨论】:

    【解决方案3】:

    如果您可以操作T,您可以模板化构造函数。

    #include <iostream>
    using namespace std;
    class B
    {
      int x;
    public:
      B (int i) : x(i) { }
      B (B && b) : x(b.x) { cout << "B moved (" << x << ")" << endl; }
      B (B const  & b) : x(b.x)  { cout << "B copied (" << x << ")" << endl; }
    };
    
    
    class A
    {
      B b;
    public:
      template<typename TB>
      A (TB && init_b) : b(std::forward<TB &&>(init_b)) { }
    };
    
    B foo (void) { B x(3); return x; }
    
    
    int main (void)
    {
      A a1(foo());
      B b1(4);
      A a2(b1);
      return 0;
    }
    

    打印

    B 搬家 (3)
    B 复制 (4)

    据我所知,参考折叠你应该拿出一个构造函数A(B&amp;) 转发到B 的复制构造函数和一个A(B&amp;&amp;) 转发到B 的移动构造函数。

    【讨论】:

    • 您的测试存在严重缺陷。您在第二行复制A,这当然复制了b 成员。此外,std::forward&lt;B&gt; 将导致移动,只有 std::forward&lt;B&amp;&gt; 会导致左值。
    • 好吧,在编辑之前这是不正确的,但使用参考折叠的模板解决方案适用于指定的情况(据我所知,通过检查 std::is_rvalue_referencestd::is_lvalue_reference)。因此,如果该答案仍有问题,请给我一个提示,而不是在没有任何 cmets 的情况下投反对票。
    猜你喜欢
    • 2016-07-08
    • 1970-01-01
    • 1970-01-01
    • 2015-05-03
    • 1970-01-01
    • 2016-10-27
    • 2020-11-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多