为什么非内置类型的返回值为const,而内置类型的const值不是const?

时间:2012-03-18 21:46:43

标签: c++ templates return-by-value

GotW #6 Const-Correctness 上的解决方案4和5提到了这一点:

Point GetPoint( const int i ) {
    return points_[i];
}
     

对于非内置返回类型,返回值通常应为常量。

     
int GetNumPoints() {
    return points_.size();
}
     

.. 因为int已经是一个rvalue并且放入'const'会干扰模板实例化,并且令人困惑,误导,并且可能会增加

我有以下问题

  1. 我们在这里干涉哪个模板实例?!
  2. 这究竟有什么误导,为什么?
  3. 为什么非内置和内置之间的区别。我认为这是一种不好的做法!

2 个答案:

答案 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返回阻止。