【问题标题】:Pass by value or universal reference按值传递或通用参考
【发布时间】:2013-06-26 09:31:07
【问题描述】:

我想开发一个带有类型擦除的小型多态类,我想知道哪个版本的模板化构造函数更好,应该使用。

我们可以传值:

class A
{
    ...
    template< typename T >
    A( T t ) { /* create the underlying model via std::move */ }
    ...
};

或者我们可以使用通用引用:

class A
{
    ...
    template< typename T >
    A( T &&t ) { /* create the underlying model via std::forward */ }
    ...
};

(如果T 不是类本身且类未被复制,则必须启用通用引用)。有任何想法吗?两个版本看起来都和我一样。

【问题讨论】:

  • 这当然取决于t 内部发生了什么。但我真的想不出你为什么选择第一个选项。这意味着在构造函数中制作t 的本地副本——即使您最终制作了一个永久副本(在数据成员中),为什么还想要一个本地副本?
  • 不,在第一个版本中你可以移动 t。
  • @jogojapan 阅读了我发布的链接:如果您仍然要进行复制,那么使用传递值实际上是有意义的
  • @stijn 不确定你到底指的是什么。但请注意,我说的是函数本地副本与数据成员中的副本。仅仅为了制作另一个副本(到数据成员中)而制作一个函数本地副本是没有意义的。至少乍一看不是。

标签: c++ pass-by-value forwarding-reference pass-by-rvalue-reference


【解决方案1】:

这些是不等价的,有时需要一个而不是另一个。 A stellar talk by Nicolai Josuttis 值得花一个小时来讨论这个问题。我强烈建议至少看一次。

就个人而言,除非您遇到特殊情况,即转换成本高昂并且您希望尽可能避免临时性,否则我建议您只传递值并std::moveing 参数。

T&amp;&amp; 更高效的情况:

struct foo {
    std::string bar;

    template <typename T>
    foo(T&& t)
        :bar(std::forward<T>(t)){}
};

对比:

struct foo {
    std::string bar;

    foo(std::string t)
        :bar(std::move(t)){}
};

当你这样做时:

int main() {
    foo f("some char*");
}

在第一种情况下(完美转发),您只需构造一个带有const char* 参数的std::string。在第二种情况下,您构造一个临时对象("some char*" 中的t)和一个空的std::string 对象,然后应用一个移动操作。这不是世界末日,但第一个版本更高效。

绝对清楚性能:

  • 第一个版本使用1分配

  • 第二个版本使用1分配1移动

move 我不是指std::move,因为它不生成任何代码(它只是一个演员表)。 move 我的意思是 实际上从字符串中移动的需要执行的代码,它是 std::string(std::string&amp;&amp;) 的一部分。

再一次 - 上面的例子是基于我在答案开头链接的谈话。 真的值得一看。

【讨论】:

    猜你喜欢
    • 2012-12-06
    • 2011-04-03
    • 2014-07-11
    • 2012-01-16
    • 2012-10-14
    • 2019-12-28
    • 2011-07-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多