C++ 返回成员变量的引用是不好的做法吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8005514/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is returning references of member variables bad practice?
提问by Matthieu M.
The below is said to be better then having first/second as public members. I believe this is nearly as bad. If you're giving a way to access a private variable outside of the class then whats the point? Shouldn't the functions be
据说下面的比第一/第二作为公共成员更好。我相信这几乎同样糟糕。如果您提供一种方法来访问类外的私有变量,那有什么意义呢?功能不应该是
T First(); void(or T) First(const T&)
Sample:
样本:
// Example 17-3(b): Proper encapsulation, initially with inline accessors. Later
// in life, these might grow into nontrivial functions if needed; if not, then not.
//
template<class T, class U>
class Couple {
Couple() : deleted_(false) { }
T& First() { return first_; }
U& Second() { return second_; }
void MarkDeleted() { deleted_ = true; }
bool IsDeleted() { return deleted_; }
private:
T first_;
U second_;
bool deleted_;
};
回答by Matthieu M.
There are several reasons why returning references (or pointers) to the internals of a class are bad. Starting with (what I consider to be) the most important:
返回对类内部的引用(或指针)不好的原因有很多。从(我认为的)最重要的开始:
Encapsulationis breached: you leak an implementation detail, which means that you can no longer alter your class internals as you wish. If you decided not to store
first_
for example, but to compute it on the fly, how would you return a reference to it ? You cannot, thus you're stuck.Invariantare no longer sustainable (in case of non-const reference): anybody may access and modify the attribute referred to at will, thus you cannot "monitor" its changes. It means that you cannot maintain an invariant of which this attribute is part. Essentially, your class is turning into a blob.
Lifetimeissues spring up: it's easy to keep a reference or pointer to the attribute after the original object they belong to ceased to exist. This is of course undefined behavior. Most compilers will attempt to warn about keeping references to objects on the stack, for example, but I know of no compiler that managed to produce such warnings for references returned by functions or methods: you're on your own.
封装被破坏:你泄露了一个实现细节,这意味着你不能再随心所欲地改变你的类内部。
first_
例如,如果您决定不存储,而是动态计算它,您将如何返回对它的引用?你不能,因此你被卡住了。不变量不再可持续(在非常量引用的情况下):任何人都可以随意访问和修改引用的属性,因此您无法“监视”其更改。这意味着您无法维护该属性所属的不变量。本质上,你的类正在变成一个 blob。
生命周期问题随之而来:在它们所属的原始对象不复存在后,很容易保持对属性的引用或指针。这当然是未定义的行为。例如,大多数编译器会尝试警告保留对堆栈上的对象的引用,但我知道没有编译器能够为函数或方法返回的引用生成这样的警告:你是靠自己的。
As such, it is usually better not to give away references or pointers to attributes. Not even const ones!
因此,通常最好不要泄露对属性的引用或指针。甚至不是常量!
For small values, it is generally sufficient to pass them by copy (both in
and out
), especially now with move semantics (on the way in).
对于小值,通常通过复制(in
和out
)传递它们就足够了,尤其是现在使用移动语义(在传入的过程中)。
For larger values, it really depends on the situation, sometimes a Proxy might alleviate your troubles.
对于较大的值,这实际上取决于情况,有时代理可能会减轻您的麻烦。
Finally, note that for some classes, having public members is not so bad. What would be the point of encapsulating the members of a pair
? When you find yourself writing a class that is no more than a collection of attributes (no invariant whatsoever), then instead of getting all OO on us and writing a getter/setter pair for each of them, consider making them public instead.
最后,请注意,对于某些类,拥有公共成员并不是那么糟糕。封装 a 的成员有pair
什么意义?当您发现自己编写的类不过是一个属性集合(没有任何不变性)时,与其将所有面向对象都放在我们身上并为每个属性编写一个 getter/setter 对,不如考虑将它们公开。
回答by iammilind
If template
types T
and U
are big structures then return by value is costly. However you are correct that returning by reference is equivalent to giving access to a private
variable. To solve both issues, make them const
references:
如果template
类型T
和U
是大结构,则按值返回成本很高。但是,您是正确的,通过引用返回等效于授予对private
变量的访问权限。要解决这两个问题,请const
参考:
const T& First() const { return first_; }
const U& Second() const { return second_; }
P.S.Also, it's a bad practice to keep variables uninitialized inside constructor, when there is no setter method. It seems that in the original code, First()
and Second()
are wrappers over first_
and second_
which were meant for read/write both.
PS此外,当没有setter方法时,在构造函数中保持变量未初始化是一种不好的做法。似乎在原始代码中,First()
并且Second()
是包装器,first_
并且second_
用于读/写。
回答by Ramesh Kadambi
The answer depends on what one is trying to do. Returning references are a convenient way to facilitate mutation of data structures. A good example is the stl map. It returns reference to the element i.e.
答案取决于人们试图做什么。返回引用是一种促进数据结构变异的便捷方式。一个很好的例子是 stl 映射。它返回对元素的引用,即
std::map<int,std::string> a;
a[1] = 1;
nothing to stop you from doing
没有什么可以阻止你做
auto & aref = a[1];
Is it necessarily a bad practice? I would not think so. I would say, if you can do without it do so. If it makes life more convenient and efficient use it and be aware of what you are doing.
这一定是一种不好的做法吗?我不会这么认为。我会说,如果你可以没有它就这样做。如果它使生活变得更加方便和高效,请使用它并注意您在做什么。