为啥 const 方法不能返回非常量引用?
Posted
技术标签:
【中文标题】为啥 const 方法不能返回非常量引用?【英文标题】:Why can't a const method return a non-const reference?为什么 const 方法不能返回非常量引用? 【发布时间】:2014-06-21 22:50:55 【问题描述】:为什么下面的方法getRanks()
编译不出来,如何优雅的修复呢?
我想要做的就是定义一个返回成员引用的成员访问器方法。参考不是const
,因为我稍后可能会修改它所指的内容。但是由于成员方法没有修改对象,所以我声明为const
。编译器(clang,std=c++11)然后坚持认为存在“删除限定符”的“引用绑定”。但我不会放弃预选赛,是吗?如果我是,为什么:
struct teststruct
vector<int> ranks;
vector<int>& getRanks()const
return ranks;
;
现在,如果我更改 return 语句以丢弃 const,则代码编译:
return const_cast<vector<int>&>(ranks);
但是“ranks”首先不应该是 const,我不明白为什么我需要 const_cast const 。我什至不知道这样做是否安全。
不管怎样,有没有更清洁的方法可以写这个方法?有人可以解释为什么这种简单的常识方法会失败吗?我确实想声明getRanks()
方法“const
”,以便我可以从其他const
方法中调用它。
【问题讨论】:
teststruct const x; x.getRanks().emplace_back();
-> UB.
【参考方案1】:
const
成员函数背后的想法是您应该能够在 const
对象上调用它们。 const
函数不能修改对象。
假设你有一堂课
class A
int data;
void foo() const
;
关于对象和函数调用:
A const a;
a.foo();
在A::foo
内部,this->data
被视为其类型为int const
,而不是int
。因此,您无法在A:foo()
中修改this->data
。
以您的示例为例,getRanks()
中的this->ranks
类型将被视为const vector<int>
而不是vector<int>
。由于不允许将const vector<int>
自动转换为vector<int>&
,因此当您将函数定义为时编译器会报错:
vector<int>& getRanks()const
return ranks;
如果你将函数定义为:
const vector<int>& getRanks()const
return ranks;
因为const vector<int>
可以自动转换为const vector<int>&
。
【讨论】:
【参考方案2】:ranks
是 const
,因为封闭对象 (*this
) 是 const
,因此您必须返回对 std::vector<int> const
的引用。
如果你想让客户端修改向量(从而影响成员),那么getter不应该是const
。请注意,getter 无论如何都是愚蠢的,因为 ranks
已经是公共数据成员。
【讨论】:
如果 getter 不是 const,则不能从 const 方法调用。但我想这样做,我想有时从 const 方法调用它,有时从 non_const 方法调用它。 @kdog 然后创建两个 getter,一个 const 和一个 non-const。 唉std::vector::operator[]
.【参考方案3】:
您正在返回对ranks
的引用,它是teststruct
的成员。这意味着任何获得此引用的人都可以修改teststruct
对象的内部结构。所以const
是个谎言。
不要抛弃const
。取而代之的是,决定您是希望函数为 const
并返回 ranks
或 const
引用的副本,还是非 const
并返回可变引用。如有必要,您始终可以同时拥有两者。
【讨论】:
但是等等。我认为方法声明中分号之前的“const”只是意味着该方法 ITSELF 没有修改它是成员函数的对象。如果我记得的话,这就是 Stroustrup 书中所说的。我并不是说从现在到将来返回的任何使用都不会修改对象。我只是声明函数本身不会。而且我确实希望返回一个可以修改的参考,而不是一个副本! const_cast 的想法也可以安全使用吗? @kdog 好吧,这将允许该方法间接导致对象被修改。const_cast
的想法并不安全,因为编译器可以根据它认为不会被修改的事实做出假设。
与其说“const
是个谎言”,不如说“const
/return 类型破坏了 const 的正确性”。
不,编译器应该在 v.push_back(42) 行给出错误,而不是在 getRanks() 行......尽管我开始看到这个问题。为什么这对我来说如此令人困惑和违反直觉,而对其他人来说却很明显;-)
@kdog 成员函数的const
表示调用该函数的对象是const
。换句话说,this 指针是 const。因为this
是常量,所以this->anything
也是const
。 getRanks
不需要返回 const &
,但需要返回具有返回类型的类型的对象。【参考方案4】:
它会删除限定符,因为您返回对 ranks
的引用。之后的任何代码都可以修改排名。例如:
auto v = teststruct.getRanks();
v[1] = 5; //assuming v.size() > 1
您可以通过返回副本来解决此问题:
vector<int> getRanks() const
或const
参考:
const vector<int>& getRanks() const
如果您希望 ranks
即使在 const
对象中也可以更改,您可以这样做:
mutable vector<int> ranks;
【讨论】:
不,这并不能解决问题,因为我以后可能想修改 getRanks() 返回的引用。我需要两个 getRank,一个 const 一个不需要吗?我只想声明 getRanks() ITSELF 不会修改对象。可以在 const 方法中调用它。 不,我不希望排名是可变的,我希望进行 const 检查。 那么听起来vector<int>& getRanks();
和const vector<int>& getRanks() const;
这两个重载就是你想要的。以上是关于为啥 const 方法不能返回非常量引用?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我不能将 const 左值引用绑定到返回 T&& 的函数?
为啥 const rvalue 限定 std::optional::value() 返回 const rvalue 引用?