通过价值或通用参考

hea*_*der 8 c++ pass-by-value pass-by-rvalue-reference forwarding-reference

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

我们可以通过价值:

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

或者我们可以使用通用参考:

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

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

Fur*_*ish 5

这些并不等同,有时候需要一个而不是另一个.一个恒星由尼古拉约祖蒂斯谈话是一个小时的价值只是在谈论这个的.我强烈建议至少观看一次.

就个人而言,除非你遇到特殊情况,转换价格昂贵而你想尽可能避免临时性,我建议只是通过价值和std::move论证来传递.

T&&更有效的案例:

struct foo {
    std::string bar;

    template <typename T>
    foo(T&& t)
        :bar(std::forward<T>(t)){}
};
Run Code Online (Sandbox Code Playgroud)

与:

struct foo {
    std::string bar;

    foo(std::string t)
        :bar(std::move(t)){}
};
Run Code Online (Sandbox Code Playgroud)

当你这样做时:

int main() {
    foo f("some char*");
}
Run Code Online (Sandbox Code Playgroud)

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

要绝对清楚表现:

  • 第一个版本使用1个分配

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

并且通过移动我不是说std::move,因为它不生成代码(它只是一个演员).通过移动我的意思是需要执行的代码实际上从字符串移动,这是一部分std::string(std::string&&).

再一次 - 上面的例子是基于我在答案开始时链接的话题.这真的值得一看.