2017-08-07 52 views
4

例如:可以std :: move()或它的显式等价于本地变量allow elision?

Big create() 
{ 
    Big x; 
    return std::move(x); 
// return static_cast<typename std::remove_reference<T>::type&&>(t) // why not elide here? 
} 

假设应用std::move()返回一个局部变量抑制移动的语义,因为编译器不能做出的一般功能的内部工作,有关情况下,当这些假设是什么做任何假设没有必要的,例如当:

  1. std::move(x)内联(可能永远)
  2. std::move(x)写为:static_cast<typename std::remove_reference<T>::type&&>(t)

根据目前的标准,实现允许应用NRVO ...

- return语句中与类返回类型,一种功能,当 表达的名称将与 (忽略cv-qualification)相同类型的非易失性自动对象( 函数参数或由 异常声明处理程序(18.3)引入的变量)作为函数返回类型,副本/移动 操作可以通过构造auto来省略matic对象直接拨入函数调用的返回对象

显然,1)和2)都不具备资格。除了使用std::move()返回本地变量的事实是多余的,为什么是必要的限制

+3

类似std :: move()的转换是在编译时执行的,所以elision是没有意义的;它们只是编译器改变如何看待类型的指示。 –

+3

[在返回的对象上使用'std :: move()'是多余的。](https://stackoverflow.com/a/14856553/501250) – cdhowie

+1

“假设本地变量上的std :: move()移动语义等因素等“ - 听起来不对。 – einpoklum

回答

2

重新阅读这个问题后,我对它有不同的理解。我把这个问题看作为'为什么std::move()抑制(N)RVO'

问题中提供的标准引用有错误的亮点。它应该是

在与类返回类型的功能,当 表达式是一个非易失性自动对象(除了 函数参数或由 引入一个可变的其它名称的返回语句

处理程序的异常声明(18.3))与同类型 (忽略CV-资质)作为函数的返回类型

什么抑制NRVO这里不是std::move()被调用,但事实上,回报值为std::move不是X,而是X&&。它与不匹配的功能签名!

+0

虽然这是很好的建议,但我不认为它实际上回答这个问题。 –

+0

@NirFriedman,我相信它的确如此,通过模仿(这是一个词?)整个问题。 – SergeyA

+1

我的意思是,因为一个问题的答案是没有必要写出最好的C++,并不意味着问题是无效的。 “不要做X”并不是对“为什么X不以这种方式工作”的回答,特别是当作者已经意识到这一点非常明确时。就目前而言,这个答案中的大部分信息已经存在于问题中。 –

2

您应该清楚确切地说明“allow elision”的含义。首先,根据“as-if”规则,编译器可以做任何想做的事情。也就是说,只要该程序集的行为正确,编译器就可以吐出所需的任何程序集。这意味着编译器可以隐藏它想要的任何构造函数,但它必须证明程序的行为是否相同,而不管构造函数是否被调用。

那么为什么elision的特殊规则?那么,这些情况下编译器可以省略构造函数调用(因此也是析构函数调用)没有证明行为是相同的。这是非常有用的,因为有许多类型的构造函数非常不平凡(比如说,string),并且编译器实际上通常不能证明他们可以安全地退出(在合理的时间范围内) (过去,优化堆分配是否合法,因为它基本上是一个全局变量的变异),甚至缺乏清晰度。

因此,我们希望有出于性能方面的考虑。然而,就行为而言,它基本上是在标准中指定一个特例。特例越大,我们向标准介绍的复杂性就越高。因此,我们的目标应该是使得允许的范围足够广泛,涵盖我们关心的有用案例,但没有更广泛的范围。

你正在接近这个:为什么不把这个特殊情况做得像实用一样大?实际上,情况恰恰相反。为了扩大elision的允许范围,需要证明它非常有价值。