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
被声明为返回易失性临时值。然而,函数体的实现细节会影响返回值的类型,并确定返回的值是否可以用作其他函数的参数。
标准是否符合此行为?
如何将其视为有用?
奖金问题:鉴于调用和实现可能在不同的翻译单元中,编译器如何知道编译时的差异?
编辑:试图重新解释这个问题。
有多少函数的结果可能比声明的返回类型更多?如果函数声明不足以确定函数返回值的行为,它甚至看起来是否可以接受?对我来说,这似乎是FUBAR的一个案例,我只是不确定是否应该责怪标准或微软的实施。
作为被调用函数的实现者,我不能指望所有调用者都知道,更不用说监视调用代码中的每一个小变化。另一方面,作为调用函数的实现者,我不能依赖被调用函数来返回在函数实现范围内恰好被声明为const的变量。
功能声明是合约。现在有什么价值?我们不是在讨论语义上等效的编译器优化,比如copy elision,这很好但不会改变代码的含义。复制ctor是否被称为 会改变代码的含义(甚至可以将代码破坏到无法编译的程度,如上所示)。要理解我在这里讨论的尴尬,请考虑上面的“红利问题”。
答案 0 :(得分:16)
我喜欢在适当的地方创建局部变量const。它帮助我清理思路并清晰地构建算法。
这确实是一种很好的做法。尽可能使用const
。但是,在这里,您不能(如果您希望移动const
对象)。
你在函数中声明一个const
对象的事实是,只要对象处于活动状态,你的对象的状态就不会被改变的承诺 - 换句话说,从来没有调用它的析构函数。在调用析构函数之前,之前不是。只要它还活着,const
对象的状态就不会改变。
但是,在某种程度上,你在某种程度上期望这个对象在从移出之前就会被范围淹没,而移动正在改变状态。您无法从const
对象移动 - 即使您不再使用该对象也不会。
可以做的是创建一个非const
对象,并仅通过对绑定到该对象的const
的引用在您的函数中访问它:
STest FuncUsingConst(int n) {
STest object_not_to_be_touched_if_not_through_reference(n);
STest const& a = object_not_to_be_touched_if_not_through_reference;
// Now work only with a
return object_not_to_be_touched_if_not_through_reference;
}
通过一些约束,您可以轻松地强制执行该函数在创建后不应该修改该对象的语义 - 除了在返回时允许它从中移动。
<强>更新强>
正如balki在评论中所建议的那样,另一种可能性是将常量引用绑定到非const临时对象(其生命周期将根据§12.2/ 5延长),并执行{{ 1}}返回时:
const_cast
答案 1 :(得分:2)
如果某个对象的复制/移动构造函数被隐式使用并且无法访问特殊成员函数,则程序格式错误
- n3485 C ++草案标准[class.copy] / 30
我怀疑你的问题出在MSVC 2012上,而不是C ++ 11。
即使没有调用它,这段代码也不合法C ++ 11:
struct STest {
STest(STest const&) = delete
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;
}
因为没有合法的方法可以将a
转换为返回值。虽然可以省略返回,但是删除返回值并不会消除复制构造函数存在的要求。
如果MSVC2012允许FuncUsingConst
进行编译,则会违反C ++ 11标准。