在this talk by Sutter 1:15:26,它出现了如下代码,
class employee{
std::string name_;
public:
template<class String, class=
std::enable_if_t< !std::is_same<std::decay_t<String>, std::string>::value > >
void set_name(String && name)
noexcept(std::isnothrow_assignable<std::string &, String>::value)
{
name_ = std::forward<String>(name);
}
}
我知道std::forward
的工作原理,如果name
是左值,name_
将获得副本构建;如果name
是右值,则name_
将构建移动。但是在幻灯片中它还说Optimized to steal from rvalues (and more)
,还有什么呢?
后来它表明这个代码似乎是所有四个实现中最快的,特别是对于char *
,任何人都有耐心去理解这些代码并解释什么是更优化以及为什么它是最快的,特别是在char *
?
答案 0 :(得分:10)
首先,请注意代码中包含一个拼写错误,即使删除了拼写错误,enable_if
约束也不会执行所讨论的内容。特别是该函数不适用于char*
,所以显然char*
并不是最快的。你可以看到我问过这个问题here以及一个'更正'的完美转发设定器(以及Howard Hinnant对此版本的认可)。
template <class String>
auto set_name(String&& name)
-> decltype(name_ = std::forward<String>(name), void()) {
name_ = std::forward<String>(name);
}
用于演示的基准测试是在set_name
上反复调用employee
,以显示成员string
重新使用其容量而非存储内存的情况每次迭代分配。基准测试中显示的高栏和短杆之间的差异是重复使用容量与每次迭代进行分配之间的差异。
使用char*
修正完美转发器的速度快的原因是char*
模板的实例化只转发char*
而不需要构建string
参数为了使用实际的set_name
对象参数调用string
。 setter中的赋值很快,因为string
实现了operator=(char*)
,它将高效的memcpy存入其现有存储中,并避免了额外的分配。
所以声明Optimized to steal from rvalues (and more)
是因为完美转发除了转发之外什么都不做。如果rvalue得到rvalue,它不仅会通过rvalue,而且它也不会转换类型,这意味着{forwordee'实现的优化(例如string
的{{1}}也会被暴露。