[英]Returning a pointer vs. passing a reference to an object to store the answer in C++
我对在这种特殊情况下使用指针还是引用有一个普遍的疑问。
假设我有一个函数,它将执行一些计算并将该值存储在对象中,以供调用者以后使用。 我可以通过使用指针或引用来实现。
虽然,我更喜欢使用引用,因为我尝试尽可能地避免使用指针,一种方法相对于另一种方法是否有优点/缺点。
使用指针的代码如下:
Node*& computeNode() {
// Do some computation before creating a node object.
Node* newNode = new Node;
newNode->member1 = xyz;
newNode->member2 = abc;
// and so on ...
return newNode;
}
使用引用的代码可以执行以下操作:
void computeNode(Node& newNode) {
// Do some computation before assigning values to the node object.
newNode.member1 = xyz;
newNode.member2 = abc;
// and so on.
}
我可以看到的差异如下:
使用指针方法时,newNode对象将在堆上分配。 因此,除非我对其调用delete,否则它不会被删除。 但是,在引用方法中,是否在堆/堆栈上分配newNode取决于调用者创建newNode对象的操作。
每当我们使用引用时,传递给函数的参数数量至少增加1。这很好,只有我发现将返回对象也传递给函数调用有点反常理,除非我在函数中命名函数这种方式对于API用户而言显而易见。
通过使用引用,我可以模拟多个对象的返回。 在指针方法中,我认为我必须将所有对象包装在另一个结构(如pair类)中,然后将其返回。 这增加了开销。
但是,我不知道通常一个人是否比另一个人更可取。 并且如果C ++中有任何函数命名约定,使开发人员知道他应该将返回对象也作为参数传递。
您可以尝试返回auto_ptr或shared_ptr。 这样可以消除删除问题。
第二种方法可能更可取,因为在您忘记delete
返回的指针的情况下,不会发生内存泄漏。
通常,以这样一种方式进行编码是一种好习惯,即分配堆内存的每个函数或对象也都会释放该内存。 您的第一个示例违反了这种做法,这使函数调用者有责任重新分配内存。 这使内存泄漏的可能性更大,因为现在每次调用该函数时,都有另一个机会忘记删除返回的指针。
在对象的大小不那么大的情况下,您可能还需要考虑按值返回对象(这将返回对象的副本)。 即使这需要创建一个副本,但如果对象不是很大,也不会影响性能。 (这种方法在将来会随着C ++ 0x move语义变得更具吸引力。)
我认为您的第一个选择应该是按值返回(或者让构造函数计算成员?):
Node computeNode()
{
Node n;
n.x = abc;
n.y = xyz;
return n;
}
这看起来效率低下,但是很有可能使用NRVO消除了复制。
如果仍然需要动态分配Node,则应按值返回指针(指针的副本):
Node* computeNode();
否则,您将返回对局部变量(指针)的引用。
我更喜欢使用第二种方法发送回信息(如您所说,无需使用额外的结构即可进行多次“返回”),并且通常返回错误或成功代码 。
另外,我将纯输入参数设置为const &
以区分输入变量和输出变量。
您可以通过使用const引用按值返回并在某些情况下避免复制:
Node computeNode() {
// Do some computation before creating a node object.
Node newNode;
newNode.member1 = xyz;
newNode.member2 = abc;
return newNode;
}
const Node &n = computeNode();
临时对象在computeNode中的生存期已扩展到引用n的范围
如果这些替代方案确实是给定的,则不清楚为什么您根本需要引用/指针。 您也可以按值返回:
Node computeNode() {
// Do some computation before creating a node object.
Node newNode;
newNode.member1 = xyz;
newNode.member2 = abc;
return newNode;
}
尽管有许多人认为,但这实际上并不是很低效,因为编译器可以(并且将!)淘汰大多数不必要的副本 。
从语义上讲,这是您想要的解决方案,除非节点也存储在其他位置,并且您需要保留引用身份。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.