c++ - 为什么在使用之前需要转换通用引用的参数?

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

lecture about universal references ,Scott Meyers(大约第 40 分钟)说,通用引用的对象在使用之前应转换为实型。换句话说,只要有通用引用类型的模板函数,就应该在使用运算符和表达式之前使用 std::forward,否则可能会复制对象。

我的理解是在下面的例子中:

#include <iostream>

struct A
{
  A() { std::cout<<"constr"<<std::endl; }
  A(const A&) { std::cout<<"copy constr"<<std::endl; }
  A(A&&) { std::cout<<"move constr"<<std::endl; }
  A& operator=(const A&) { std::cout<<"copy assign"<<std::endl; return *this; }
  A& operator=(A&&) { std::cout<<"move assign"<<std::endl; return *this; }

  ~A() { std::cout<<"destr"<<std::endl; }

  void bar()
  {
    std::cout<<"bar"<<std::endl;
  }
};

A getA()
{
  A a;
  return a;
}

template< typename T >
void callBar( T && a )
{
  std::forward< T >( a ).bar();
}

int main()
{
  {
    std::cout<<"\n1"<<std::endl;
    A a;
    callBar( a );
  }

  {
    std::cout<<"\n2"<<std::endl;
    callBar( getA() );
  }
}

正如预期的那样,输出是:

1
constr
bar
destr

2
constr
move constr
destr
bar
destr

真正的问题是为什么需要这样做?

std::forward< T >( a ).bar();

我在没有 std::forward 的情况下尝试过,它似乎工作正常(输出是相同的)。

同样,为什么他建议在带有右值的函数内部使用 move ? (答案与 std::forward 相同)

void callBar( A && a )
{
  std::move(a).bar();
}

我知道 std::movestd::forward 都只是转换为适当的类型,但在上面的例子中真的需要这些转换吗?

奖励:如何修改示例以生成传递给该函数的对象的拷贝?

最佳答案

它是必需的,因为 bar() 可能会分别为右值和左值重载。这意味着它可能会做一些不同的事情,或者完全不允许,这取决于您是否正确地将 a 描述为左值或右值,或者只是盲目地将其视为左值。现在,大多数用户不使用此功能,也没有接触过它,因为最流行的编译器不支持它——甚至 GCC 4.8 也不支持右值 *this。但它是标准的。

关于c++ - 为什么在使用之前需要转换通用引用的参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12837327/

相关文章:

c++ - 运行时字符串错误 C++

c++ - 返回字符串的散点回文数

c++ - std::memory_order 和三个线程的同步谜题

c++ - 测试一个对象是否已经从

c++ - 为什么在返回兼容类型时需要显式 std::move?

c++ - 在实践中何时调用 move 构造函数?

c++ - 在析构函数中执行任务

c++ - 构建错误:未定义对 `yyFlexLexer::yyFlexLexer(std::istream*, std::ostream*) 的引用

c++ - 在 LGPL 下的商业产品中使用 Qt 时如何允许私有(private)修改

C++11:参数包扩展计数器