返回对C+中可能更改的数据的引用+; 在C++中,返回一个常数引用可能是一个好主意吗?例如,假设您有一个函子: template<class T> struct f { f(const T& init) data{init} {} const T& operator() () { return ++data; } private: T data; }; 模板 结构f{ f(const T&init)数据{init}{ 常量T&运算符(){return++data;} 私人: T数据; };

返回对C+中可能更改的数据的引用+; 在C++中,返回一个常数引用可能是一个好主意吗?例如,假设您有一个函子: template<class T> struct f { f(const T& init) data{init} {} const T& operator() () { return ++data; } private: T data; }; 模板 结构f{ f(const T&init)数据{init}{ 常量T&运算符(){return++data;} 私人: T数据; };,c++,c++11,functor,C++,C++11,Functor,作为我关注的一个例子,函数能否获取返回数据的地址?当值“在客户端背后”更改时,这会给我带来一个严重的惊喜。(或者返回的引用是否算作右值,从而使查找其地址变得非法?)我或其他客户端还会遇到什么其他问题 tl;dr:上面的函子是个好主意吗?对于基元类型,通过常量引用返回通常没有意义,因为引用将同样大(就内存大小而言),或者甚至可能比基元类型本身更大 也可以考虑当代码仍在使用时删除代码>结构SF>代码>的实例——它将引用删除的数据!这从来都不是好事,需要加以防止 < >仅针对较大的用户定义类型,我建议

作为我关注的一个例子,函数能否获取返回数据的地址?当值“在客户端背后”更改时,这会给我带来一个严重的惊喜。(或者返回的引用是否算作右值,从而使查找其地址变得非法?)我或其他客户端还会遇到什么其他问题


tl;dr:上面的函子是个好主意吗?

对于基元类型,通过常量引用返回通常没有意义,因为引用将同样大(就内存大小而言),或者甚至可能比基元类型本身更大

也可以考虑当代码仍在使用时删除代码>结构SF>代码>的实例——它将引用删除的数据!这从来都不是好事,需要加以防止

< >仅针对较大的用户定义类型,我建议考虑这种模式(避免复制可能带来性能优势,或者可以帮助保持较小的内存占用),但是,也只有当您能够保证返回引用的对象比使用引用的对象活得更长或至少与使用引用的对象一样长时,才可以使用它

关于调用方能够修改值:仅获取这样一个表达式的地址是不够的;调用者还必须const cast引用以使其可修改(检查reference是否存在)。除了一些罕见的情况外,
const_cast
是一种非常糟糕的做法,因此通常会导致所有警铃在审查期间响起。所以这个方面不是你必须考虑的太多。

函数能否获取返回数据的地址

对。i、 e.
const int*ptr=&my_f()请注意,您仍然可以避免客户端无意中修改数据并破坏类不变量,因为您无法修改由
常量int*
指向的数据,除非您开始智胜类型系统并将其强制转换为
int*

这将在以后“在客户背后”更改值时引起严重的意外

客户机仅根据函数的签名就知道函数返回引用。如果客户希望拥有自己的副本供他们修改或防止您的类修改,那么他只需执行
int my_own_copy=my_f(),他得到了一份副本

或者它算作一个右值,使得查找其地址非法

除非您执行类似于
const int&operator(){return data++;/*注意:postfix*/}
的操作,否则客户端将不会非法引用无效数据

我或其他客户可能会遇到哪些其他问题

一个常见的问题是,客户端引用的生存期将超过具有引用数据的对象的生存期。尽管如此,对于其他引用,这仍然是正确的,因此客户不必学习另一条准则来保持引用的有效性

tl;上面的函子是个好主意吗


tl;医生:是的。如上所述,如果客户需要,他仍然可以得到一份副本,或者如果他不想承担复制潜在大数据的成本,他可以选择引用数据。

hmm,我担心我会得到第一个批评,因为我使用了
int
作为一个简单的例子。如果我将
int
模板化,这会如何改变您的答案?一点也不会。我指的是原语和用户定义的类型,正如您所提到的,将常量ref返回到可以修改的数据段是非常危险的。你为什么要这么做?您是否考虑了特定的用例?我可能会使用它来构建一个具有状态的迭代器。由于每次为
iterator::operator*()
构建整个返回值都是低效的(O(logn)),因此我考虑将预构建的值存储在迭代器中,虽然与只有指针的“廉价”迭代器相比有点贵,但存储的数据会有恒定的时间更新。有趣的是,当客户机推进迭代器并期望其来自
iterator::operator*()
的旧返回值在那里时会发生什么?那么,这会发生吗?应该吗?信息丰富,谢谢。如果我要按值返回,会不会被可以执行返回值省略的编译器优化掉,或者我不知道的其他一些聪明的优化?@Thirty340仅当为了正确性而确实需要按值返回时才按值返回(例如,返回局部变量)。对于可以安全地返回对数据的常量引用,然后返回常量引用的场景。注意另一个答案的建议,不要通过引用原语类型返回,这也很有帮助。好的,好的经验法则。我对我最初的问题做了一个评论,如果您好奇的话,可以更详细地解释我的特定用例。