我想开发一个带有类型擦除的小型多态类,我想知道哪个版本的模板化构造函数更好,应该使用。
我们可以通过价值传递:
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
不是类本身并且未复制类,则必须启用通用引用)。有任何想法吗?这两个版本都与我相同。
答案 0 :(得分:5)
这些不是等效的,有时需要一个相对于另一个。 A stellar talk by Nicolai Josuttis一小时值得谈论。我强烈建议至少观看一次。
就个人而言,除非遇到特殊情况,否则转换成本很高,并且您希望尽可能避免临时使用,我建议您仅按值传递并std::move
输入参数。
在T&&
更有效的情况下:
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*");
}
在第一种情况(完美转发)中,您只需使用std::string
参数构造一个const char*
。在第二种情况下,您将构造一个临时对象(来自t
的{{1}}和一个空的"some char*"
对象,然后应用一个移动操作。这不是世界末日,但第一个版本效率更高。
要绝对清楚性能:
第一个版本使用 1个分配
第二个版本使用 1个分配和1个移动
并且通过 move 并不是std::string
,因为它不生成任何代码(只是强制转换)。 move 的意思是实际上需要从字符串移出的代码,该字符串是std::move
的一部分。
再次-上面的示例基于我在答案开头链接的谈话。 真的值得一看。