接收器的值传递或传递通用参考?

时间:2014-05-22 09:12:19

标签: c++ c++11 move forwarding


WRT。建议的重复"Is pass-by-value a reasonable default in C++11?" - 那里的问题的答案都没有提到"通用参考"构造函数版本,所以I确实无法看到重复。考虑重新开放。


我熟悉移动语义,试验它。请看一下这段(可编辑的)代码:

#include <iostream>
#include <string>

struct my_str {
  std::string s;

  my_str(const std::string & str): s(str) { std::cout << "  my_str parameter ctor" << std::endl; }
  my_str(const my_str & o): s(o.s)        { std::cout << "  my_str copy ctor" << std::endl; }
  my_str(my_str && o): s(std::move(o.s))  { std::cout << "  my_str move ctor" << std::endl; }
};

template <typename T>
my_str build_ur(T && s) {
  return my_str(std::forward<T>(s));
}

my_str build_val(my_str s) {
  return my_str(std::move(s)); 
}

int main() {
  my_str s1("hello");
  my_str s2("world");

  std::cout << "Building from universal reference (copy):" << std::endl;
  build_ur(s1);
  std::cout << "Building from universal reference (move):" << std::endl;
  build_ur(std::move(s1));

  std::cout << "Building from value (copy):" << std::endl;
  build_val(s2);               
  std::cout << "Building from value (move):" << std::endl;
  build_val(std::move(s2));    

  std::cout << std::endl;
  return 0;
}

输出:

g++-4.8 -std=c++11 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
  my_str parameter ctor
  my_str parameter ctor
Building from universal reference (copy):
  my_str copy ctor
Building from universal reference (move):
  my_str move ctor
Building from value (copy):
  my_str copy ctor
  my_str move ctor
Building from value (move):
  my_str move ctor
  my_str move ctor

http://coliru.stacked-crooked.com/a/3be77626b7ca6f2c

这两个功能在两种情况下都能正确完成。 by-value函数再次调用move构造函数,但这应该很便宜。你能评论一种模式应该优先于另一种模式的情况吗?

1 个答案:

答案 0 :(得分:0)

您的两个版本build执行不同的操作。

版本1:&#34;创建副本&#34;

my_str build_plain(my_str s) {
  return my_str(std::move(s)); 
}

使用复制构造函数创建参数的副本。然后将此副本移动到结果对象中。赋予该函数的对象之后将有效。这个函数没那么有意义,因为my_str build(my_str s) { return s; }会实现同样的目的。

版本2:&#34;移动它&#34;

template <typename T>
my_str build_templated(T && s) {
  return my_str(std::forward<T>(s));
}

将参数对象移动到新对象中并返回该新对象。之后给予该函数的对象将无效!这是移动物体的经典案例。


总结:版本1(几乎)等同于my_str t = s;,而版本2(几乎)等同于my_str t = std::move(s);