移动由逗号运算符抑制的构造函数
Posted
技术标签:
【中文标题】移动由逗号运算符抑制的构造函数【英文标题】:Move constructor suppressed by comma operator 【发布时间】:2012-08-30 13:37:56 【问题描述】:这个程序:
#include <iostream>
struct T
T()
T(const T &) std::cout << "copy constructor ";
T(T &&) std::cout << "move constructor ";
;
int main()
([](T t) -> T return t; )(); std::cout << '\n';
([](T t) -> T return void(), t; )(); std::cout << '\n';
([](T t) -> T return void(), std::move(t); )(); std::cout << '\n';
当由 gcc-4.7.1 编译时输出 (link):
move constructor
copy constructor
move constructor
为什么逗号操作符会有这种效果?标准说:
5.18 逗号运算符 [expr.comma]
1 - [...] 类型 结果的和值是右操作数的类型和值;结果与其右操作数[...]具有相同的值类别。如果右操作数的值是临时的,则结果是临时的。
我是否遗漏了一些允许逗号运算符影响程序语义的东西,或者这是 gcc 中的错误?
【问题讨论】:
我认为是命名对象通常不能被移动(见那里的#2),但是return t;
有一个明显的漏洞,它可以破坏命名的-对象规则并移动(参见#1)。但我不确定。如果有人确定,请发布答案。
顺便说一句,这似乎是open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2125
@Matthew 谢谢!它已解决“扩展”问题,因此委员会愿意对其进行更改,但不认为当前的行为是错误。
对。看起来 CWG 认为这不是一个错误并将其踢给了 EWG,最近在没有太多动静的情况下进行了讨论(基本上,我们同意它是 NAD,但我们愿意进行改进)。我不确定谁(如果有的话)正在积极追求这一点,但欢迎您通过标准提案摇摆并四处询问。
【参考方案1】:
自动移动基于复制省略的资格:
§12.8 [class.copy] p32
当满足或将满足省略复制操作的条件时,除了源对象是函数参数的事实,并且要复制的对象由左值指定时,重载决策选择构造函数首先执行复制,就好像对象由右值指定一样。 [...]
当返回表达式是自动对象的名称时,允许复制省略。
§12.8 [class.copy] p31
在具有类返回类型的函数中的
return
语句中,当表达式是非易失性自动对象的名称时(函数或 catch 子句参数除外)与函数返回类型相同的 cv 非限定类型,可以通过将自动对象直接构造到函数的返回值中来省略复制/移动操作
插入逗号运算符后,表达式不再是自动对象的名称,而只是对一个对象的引用,从而抑制了复制省略。
【讨论】:
【参考方案2】:t
是一个局部的命名变量,因此是一个左值。逗号操作符的行为与记录一致。
相反,您应该问为什么 return t;
允许 t
绑定到右值引用 - 这才是真正的魔力。
【讨论】:
以上是关于移动由逗号运算符抑制的构造函数的主要内容,如果未能解决你的问题,请参考以下文章