【发布时间】:2013-04-11 23:13:51
【问题描述】:
struct STest : public boost::noncopyable {
STest(STest && test) : m_n( std::move(test.m_n) ) {}
explicit STest(int n) : m_n(n) {}
int m_n;
};
STest FuncUsingConst(int n) {
STest const a(n);
return a;
}
STest FuncWithoutConst(int n) {
STest a(n);
return a;
}
void Caller() {
// 1. compiles just fine and uses move ctor
STest s1( FuncWithoutConst(17) );
// 2. does not compile (cannot use move ctor, tries to use copy ctor)
STest s2( FuncUsingConst(17) );
}
上面的示例说明了在 C++11 中,正如在 Microsoft Visual C++ 2012 中实现的那样,函数的内部细节如何修改其返回类型。直到今天,我的理解是返回类型的声明是程序员需要知道的,以了解如何处理返回值,例如,当作为参数传递给后续函数调用时。 不是这样。
我喜欢在适当的地方创建局部变量const。它帮助我整理思路并清晰地构建算法。但请注意返回声明为const 的变量!即使不再访问该变量(毕竟执行了 return 语句),并且即使声明为 const 的变量早已超出范围(参数表达式的评估已完成),它无法移动,因此将被复制(如果无法复制,则编译失败)。
这个问题与另一个问题Move semantics & returning const values 有关。不同之处在于,在后者中,函数被声明为返回一个const 值。在我的示例中,FuncUsingConst 被声明为返回一个 volatile 临时变量。然而,函数体的实现细节会影响返回值的类型,并决定返回值是否可以作为其他函数的参数。
此行为是否符合标准?
这怎么能被视为有用?
额外问题:考虑到调用和实现可能在不同的翻译单元中,编译器如何在编译时知道差异?
编辑:尝试改写问题。
一个函数的结果怎么可能比声明的返回类型更多?函数声明不足以确定函数返回值的行为,这似乎完全可以接受吗?对我来说,这似乎是 FUBAR 的一个案例,我只是不确定是该责怪标准还是微软的实施。
作为被调用函数的实现者,我不可能知道所有的调用者,更不用说监控调用代码的每一个微小变化。另一方面,作为调用函数的实现者,我不能依赖被调用函数不返回一个恰好在函数实现范围内声明为 const 的变量。
函数声明是一种契约。现在值多少钱?我们在这里讨论的不是语义等价的编译器优化,比如复制省略,这很好,但不会改变代码的含义。不管复制ctor是否被调用确实改变了代码的含义(甚至可以将代码破坏到无法编译的程度,如上图所示)。为了理解我在这里讨论的尴尬,请考虑上面的“奖金问题”。
【问题讨论】:
-
如果不查看 Std,我会说应该调用复制 ctor 和移动 ctor。您确定仅调用了复制ctor吗?
-
为
return语句创建的临时文件只能被省略“当表达式是具有相同cv的非易失性自动对象(函数或catch子句参数除外)的名称时-作为函数返回类型的非限定类型” [class.copy]/31。这里不是这种情况,所以在FuncUsingConst中,应该复制对象a,然后在调用之后调用move ctor。 -
我根本不希望调用复制 ctor,也不是在讨论复制省略。我“只是”想查看临时的移动语义,即
FuncUsingConst的返回值,并传递给STest移动ctor。 -
我不完全确定我是否在这里正确解释了标准:在我看来,
return语句中使用的类型(a的类型)必须与函数返回类型,包括用于省略副本的 cv 限定符。如果这是正确的,您的编译器应该抱怨从a到非常量临时STest的复制是不允许的。FuncUsingConst的返回类型始终是非常量STest。 -
不确定我是否正确解释了您的问题,但您似乎在问为什么编译器会尝试通过复制构造函数而不是移动构造函数从 FuncUsingConst 的结果初始化 s2?你抱怨这种方式影响函数接口的实现?但这不是正在发生的事情。编译器尝试从 const 局部变量初始化 FuncUsingConst 的结果,但这样做失败。和外界完全没有关系。事实上,即使你从不调用 FuncUsingConst,这段代码也应该编译失败。
标签: c++11 return constants move-semantics rvalue-reference