GotW #6 Const-Correctness 上的解决方案4和5提到了这一点:
Point GetPoint( const int i ) { return points_[i]; }
对于非内置返回类型,返回值通常应为常量。
int GetNumPoints() { return points_.size(); }
.. 因为int已经是一个rvalue并且放入'const'会干扰模板实例化,并且令人困惑,误导,并且可能会增加。
我有以下问题
答案 0 :(得分:4)
Return-by-value should normally be const for non-builtin return types ..
这是不正确的 - GotW中相对较少的错误之一。 const
rvalues在C ++ 03中是有问题的,在C ++ 11中肯定非常糟糕。
问题在于,在C ++ 03中,rvalues可以在它们上面调用任何成员函数 - 甚至是非const。这很好,因为你可以“交换”或执行方法链和其他东西,这些都是完美的并且具有绝对意义,但它也很糟糕,因为当你做一些愚蠢的事情时编译器无法抓住你,比如分配给它或什么东西。一般来说,限制每个人做好事是一个坏主意,因为调用者可能做一些愚蠢的事情。意图很好,但这不对。
在C ++ 11中,这是固定的,因为你可以禁止在rvalues上调用成员函数,其次,因为为了使移动语义正常工作,rvalue必须是可变的。如果是const
,则无法从右值获取资源。
正如一个注释,这是不同的原因是因为原始类型总是在语言中内置了特殊的措辞,例如将rvalues分配为非法,因此无需通过设置const
来尝试强制执行。
至于模板实例化,我实际上是不确定的。我开始编写C ++时已经知道这种做法很糟糕,所以这不是我必须处理的事情。
答案 1 :(得分:3)
就个人而言,我不同意将const
放在与移动语义无关的返回值上的建议:该值已经是一个rvalue,因此没有太大的意外修改它的危险。这是为什么要在非内置类型上放置const
的部分原因:它们可能包含某种类型的后门。例如,std::vector<T>
有一个swap()
方法,可用于“窃取”非常量右值的内容:
std::vector<int> f();
std::vector<int> value;
f().swap(value);
类似地,流有一些成员运算符,允许您将它们与某些内置函数一起使用,这些函数可以有效地从流中提取引用,例如:
std::string word;
std::istringstream("hello, world") >> std::skipws >> word;
如果没有std::skipws
,则流是一个rvalue,它不能绑定到std::operator>> (std::istream&, std::string&)
的第一个参数,但是使用操作符的成员运算符会返回对该流的非const引用。
内置类型的const
实际上根本没有效果。特别是,当将函数的结果传递给函数模板时(在C ++ 2003中),它无法区分传递的const
或非const
返回。因此,看起来好像const
对内置回报有影响,尽管实际上并没有。
正如我所说的,我不同意这条规则,在C ++ 2011中它肯定不成立,因为你想要能够移出非内置的无论如何由const
返回阻止。