1

在 C++ 中,返回对可能更改的数据的常量引用是个好主意吗?例如,假设你有一个函子:

template<class T>
struct f {
  f(const T& init) data{init} {}
  const T& operator() () { return ++data; }
private:
  T data;
};

作为我关心的一个例子,一个函数可以获取返回数据的地址吗?当值在“客户背后”发生更改时,这会带来令人讨厌的惊喜。(或者返回的引用是否计为右值,使得查找其地址是非法的?)我或其他客户可能会遇到哪些其他问题?

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

4

2 回答 2

2

函数可以获取返回数据的地址吗?

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

当值在“客户背后”发生更改时,这会带来令人讨厌的惊喜。

客户端将仅根据函数的签名知道该函数返回一个引用。如果客户想要一份他们自己的副本供他们修改或防止它被您的班级修改,那么他可以这样做int my_own_copy = my_f();,他得到一份副本。

还是它算作一个右值,使得查找它的地址是非法的?

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

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

一个常见的问题是客户端引用的生命周期将超过具有引用数据的对象的生命周期。尽管如此,这对于其他参考仍然是正确的,因此客户不必学习另一个指南,他们的参考仍然有效。

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

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

于 2013-10-15T07:22:30.757 回答
0

对于原始类型,通过 const 引用返回通常没有真正意义 - 因为引用将同样大(就内存大小而言),或者甚至可能大于原始类型本身。

struct f此外,考虑在引用仍在使用时删除实例的情况- 它将引用已删除的数据!这从来都不是好事,需要加以预防。

仅对于较大的用户定义类型,我建议考虑这种模式(避免复制可能会带来性能优势或有助于保持较小的内存占用),但也仅在您可以保证返回引用的对象时才使用它将比使用引用的对象寿命更长或至少一样长。

关于调用者可以修改值:只取这样一个表达式的地址是不够的;调用者还必须对引用进行 const 转换以使其可修改(检查const_cast的引用)。除了一些极少数情况,这const_cast是非常糟糕的做法,因此通常应该在例如审查期间引起所有警钟响起。所以这方面不是你必须考虑太多的事情。

于 2013-10-15T07:14:54.770 回答