【问题标题】:Pass By Copy Implications [duplicate]通过复制含义[重复]
【发布时间】:2014-05-19 23:10:05
【问题描述】:

好的,我正在考虑下面的 C++ 代码:

foo (std::string str) {
  // do whatever
}

foo(const char *c_str) {
  foo(std::string(c_str));
}

我看了这段代码,认为它需要重写才能通过引用传递。基本上,我担心构造函数会被调用两次,一次是在 const char * 版本的 foo 中,另一次是在参数作为 std::string 传递给 foo 时,因为它被设置为通过副本传递。我的问题是:我是对的,还是 g++ 足够聪明,可以在 c 字符串版本中采用构造函数并将其称为好?好像 g++ 做不到,但我只是希望真正知道的人能澄清一下。

【问题讨论】:

  • 你想委托建设吗?
  • 我担心如果我将其更改为通过引用传递,我所引用的内容可能会被更改......

标签: c++ g++


【解决方案1】:

理论上将涉及两个构造函数(一个用于创建临时构造函数,一个用于传递拷贝的拷贝构造函数);在实践中,编译器被明确允许执行复制省略(C++11 §12.8 ¶32)。

但是你不需要开始这两个重载。

通常的方法是只拥有一个采用const std::string & 的函数版本。如果调用者已经有一个std::string,则不会执行复制,因为我们是通过引用传递的。相反,如果它有一个char *,则会创建一个临时的std::string(因为它有一个来自const char* 的非显式构造函数)并传递给函数(因为const 引用可以绑定到临时变量)。

【讨论】:

  • 即使构造函数有副作用,编译器也可以省略副本。
  • @Richard:当然是 RVO 和 NRVO,参数我不知道。
  • 只要副本的来源未绑定到名称,就可以使用相同的机制来删除副本。 IE。这是暂时的
  • @RichardHodges:我刚刚检查了标准,你是正确的(它在 C++11 §12.8 ¶32,第三个要点);我会修正我的答案。
  • 这是一个容易错过的细节。我必须读两遍才能看到它。
【解决方案2】:

你可以习惯性地写

foo (std::string const& str) {
  // do whatever
}

不需要重载,因为你可以隐式地构造一个临时的:

foo("yes");

如果您打算将参数的值存储在某处,则可以采用右值引用:

foo (std::string && str) {
   my_member = std::move(str);
}

但为了避免过载爆炸,按值取参数通常是一个很好的中间地带:

不管关于 idomatic 参数传递的所有这些好建议,是的,编译器可以根据 as-if 规则优化掉虚假副本(尽管复制构造函数必须是可访问的,就好像复制已执行)

【讨论】:

    【解决方案3】:

    由于传递给foo 的临时参数未命名,因此直接构造到参数中似乎是一个相当简单的优化,消除了副本,尽管标准不能保证这一点(因为没有优化)。

    但是,更一般地说,您应该通过常量引用传递除非您的函数已经获取了参数本身的副本(例如,可能要复制和变异),

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-12-17
      • 1970-01-01
      • 2021-12-26
      • 2014-04-15
      • 2011-07-07
      • 2016-01-23
      • 2019-07-12
      相关资源
      最近更新 更多