繁体   English   中英

返回指针与将引用传递给对象以将答案存储在C ++中

[英]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.  
}

我可以看到的差异如下:

  1. 使用指针方法时,newNode对象将在堆上分配。 因此,除非我对其调用delete,否则它不会被删除。 但是,在引用方法中,是否在堆/堆栈上分配newNode取决于调用者创建newNode对象的操作。

  2. 每当我们使用引用时,传递给函数的参数数量至少增加1。这很好,只有我发现将返回对象也传递给函数调用有点反常理,除非我在函数中命名函数这种方式对于API用户而言显而易见。

  3. 通过使用引用,我可以模拟多个对象的返回。 在指针方法中,我认为我必须将所有对象包装在另一个结构(如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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM