我已经阅读了很多有关此问题的stackoverflow答案,我对答案不太满意,所以我想在这里收集它们。
当使用非基元和复杂对象调用函数时,通常建议通过引用传递它们,除非参数可能为NULL。这主要是因为引用保证具有值,因此您不必检查参数引用是否为NULL。
当函数的返回值是非基本和复杂的对象时,通常应该返回一个指针,因为很容易混淆一个返回引用的函数和一个返回值的函数,因为它们在调用时看起来是相同的。 / p>
以此类为例
struct Rectangle
{
int x, y;
int width, height;
Rectangle(int x_, int y_, int width_, int height_)
: x(x_)
, y(y_)
, width(width_)
, height(height_)
{
}
};
class Image
{
public:
Image()
: dimensions(0, 0, 0, 0)
{}
~Image();
void SetDimensions (const Rectangle& newDimensions) // Pass by reference is recommended practice
{
dimensions = newDimensions;
}
Rectangle GetDimensions() // Returning by value is usually the best practice in this case
{
return dimensions;
}
private:
Rectangle dimensions;
};
这些是函数参数和返回类型中引用与指针的最佳实践吗?如果没有,请解释原因。
编辑1:更改了GetDimensions()以返回值,因为它被认为是有效的
答案 0 :(得分:7)
引用是引用,值是值。它们具有不同的语义,只考虑保存复制操作的性能可能会成为一个严重的问题。
更具体地说,在理论上,只有当接收者关心对象的身份(而不仅仅是关于值)时才应该使用引用。如果标识不重要且被调用的函数/方法仅关注值,则应使用值。
如果您完全确定自己不会遇到别名或生存期问题,那么您可能会决定传递一个const引用保存复制操作的值。
在this answer中有一个详细的例子(顺便提一下,也是在讨论矩形),你可能会遇到一些非常微妙的错误。应该使用值代替。还要注意,在处理别名和生命周期问题时,const-correctness不会有任何帮助。
答案 1 :(得分:5)
关于处理对象访问和表示的最佳做法是使用此顺序:
这适用于代码和类成员中对象的定义,以及将它们传递给函数和从函数传递它们。基本上无处不在。
并且“真的不能”我的意思是写一个可编译的代码是不可能的。我不认为在编译器的当前状态,标准及其优化功能中更改此顺序是否有任何实际开销。
一点解释。
在人们遇到返回变量的麻烦之前,现在我们得到了RVO和NRVO。此外,c ++ 11还提供了std::function
,lambdas和move
语义。 IMO所有这一切都是为了能够使用对象和引用而不会产生任何开销,这就是为了使代码更易于维护,可读性和结构化。
有时您需要使用指针,例如在抽象类接口的情况下。智能指针有助于对象管理,在这种情况下应该是默认的选择。例如,它们处理对象的删除,因此您可以安全地使用它们与标准容器,而无需额外的努力。 “双重免费”它们也更难,或更容易发现错误。
然而,我看到SO上的一个人在某些游戏引擎上实现了他们的智能指针。他们不能使用标准库的祝福,而不得不自己做。这是你使用普通指针的时候。
答案 2 :(得分:1)
我会将SetDimensions
和GetDimensions
调整为:
// immutable access:
const Rectangle & GetDimensions() const;
// mutable access:
Rectangle & GetDimensions();
// or instead of the mutable GetDimensions():
void SetDimensions(const Rectangle & newDimensions);