如果我有一个包含许多int
,float
和enum
成员变量的类,将它们作为引用而不是副本返回是否被认为是有效和/或良好的做法,并返回不应进行更改的常量引用?还是有理由我应该将它们作为副本退回?
7 回答
没有理由返回原始类型,例如int
和float
通过引用,除非您希望允许更改它们。通过引用返回它们实际上效率较低,因为它什么都不保存(int
s 和指针通常大小相同),而取消引用实际上增加了开销。
如果它们是常量引用,也许没关系。如果它们不是常量引用,则可能不是。
至于效率——在 64 位机器上,引用将是 64 位数量(变相的指针);int
并且float
会enum
更小。如果你返回一个引用,你是在强制一个间接级别;它的效率较低。
因此,特别是对于作为返回值的内置类型,通常最好返回值而不是引用。
有些情况是必须的:
查看operator[]
任何类的重载。它通常有两个版本。变异版本必须返回一个引用。
int &operator[](int index); // by reference
int operator[](int index) const; // by value
一般来说,允许一个类(例如朋友)的受信任实体访问类成员是可以的。如果这些受信任的实体还需要修改状态,则对类成员的引用或指针是唯一的选择。
在许多情况下,引用通常会简化语法,例如,'v' 是 STL 向量。
v.at(1) = 2 vs *(v.at(1)) = 2;
这可能主要是风格或偏好的问题。不返回引用的一个原因是因为您使用 getter 和 setter 来允许您更改这些成员的实现,如果您将私有成员更改为另一种类型,或者因为可以计算而将其完全删除,那么您将不再拥有返回引用的能力,因为没有什么可引用的。
另一方面,返回非平凡类型(复合类)的引用可以加快您的代码速度而不是复制,并且您可以允许通过返回的引用分配这些成员(如果需要)。
吸气剂是用于排放的一类说Exhaust Car.emit()
,汽车刚刚创建的Exhaust
。
如果您一定要const Seat& Car.get_front_seat()
稍后再写Driver
,您可以立即注意到有问题。
正确地,您宁愿编写 Car.get_in_driver(Driver)
which 然后直接调用seat.sit_into(Driver)
.
get_front_seat
第二种方法很容易避免当您关闭车门并且您实际上将驾驶员推入关闭的车门时的尴尬情况。请记住,您只要求一个座位!:)
总而言之: 总是按值返回(并依赖于返回值优化),或者意识到是时候改变你的设计了。
背景:创建类是为了使数据可以与其访问器功能、本地化错误等耦合在一起。因此,类永远不是活动的,而是面向数据的。
进一步的陷阱:在 C++ 中,如果你通过 const ref 返回一些东西,那么你很容易忘记它只是一个 ref,一旦你的对象被破坏,你可能会留下一个无效的 ref。否则,该对象将在离开 getter 后被复制。但是编译器会避免不必要的副本,请参阅返回值优化。
这主要是一个性能问题,但从稳健性的角度来看,我会说最好返回值而不是 const 引用。原因是即使是 const 引用也会削弱封装。考虑一下:
struct SomeClass
{
std::vector<int> const & SomeInts () const;
void AddAnInt (int i); // Adds an integer to the vector of ints.
private:
std::vector<int> m_someInts;
};
bool ShouldIAddThisInt(int i);
void F (SomeClass & sc)
{
auto someInts = sc.SomeInts ();
auto end = someInts.end ();
for (auto iter = someInts.begin (); iter != end; ++iter)
{
if (ShouldIAddThisInt(*iter))
{
// oops invalidates the iterators
sc.AddAnInt (*iter);
}
}
}
因此,如果它在语义上有意义并且我们可以避免过多的动态分配,我更喜欢按值返回。
几乎, const 引用更好。对于整数等没有意义,因为您希望更改它们或因为它们与参考的大小相同(或几乎相同)。
所以是的,这是个好主意。我更喜欢另一种语言或破解我自己的 C++ 东西,只允许 var 公开(再次它只是我自己的东西)