简体   繁体   English

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

[英]Returning a pointer vs. passing a reference to an object to store the answer in C++

I have general question regarding the use of pointers vs. references in this particular scenario. 我对在这种特殊情况下使用指针还是引用有一个普遍的疑问。

Let's say that I have a function that is going to do some computation and store the value inside an object for later use by the caller. 假设我有一个函数,它将执行一些计算并将该值存储在对象中,以供调用者以后使用。 I can implement this by using either pointers or references. 我可以通过使用指针或引用来实现。

Although, I would prefer using references because I trying avoiding pointers as much as possible, are there any pros/cons of one approach over the other. 虽然,我更喜欢使用引用,因为我尝试尽可能地避免使用指针,一种方法相对于另一种方法是否有优点/缺点。

The code using Pointers would be as follows: 使用指针的代码如下:

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;  
}

The code using references could do something like this: 使用引用的代码可以执行以下操作:

void computeNode(Node& newNode) {  
   // Do some computation before assigning values to the node object.  
   newNode.member1 = xyz;  
   newNode.member2 = abc;  
   // and so on.  
}

The differences that I can see are as follows: 我可以看到的差异如下:

  1. When using the pointer method, the newNode object is allocated on the Heap. 使用指针方法时,newNode对象将在堆上分配。 So, unless I call delete on it, it is not going to get deleted. 因此,除非我对其调用delete,否则它不会被删除。 However, in the reference method, whether newNode is allocated on the Heap/Stack depends on what the caller did to create the newNode object. 但是,在引用方法中,是否在堆/堆栈上分配newNode取决于调用者创建newNode对象的操作。

  2. Whenever we use references, the number of arguments needed to pass to the function increases by at least 1. This is fine, only I find it a bit counter-intuitive to pass the return object also to a function call unless I name the function in such a way that it becomes obvious to the API user. 每当我们使用引用时,传递给函数的参数数量至少增加1。这很好,只有我发现将返回对象也传递给函数调用有点反常理,除非我在函数中命名函数这种方式对于API用户而言显而易见。

  3. By using references, I can simulate the return of multiple objects. 通过使用引用,我可以模拟多个对象的返回。 In the pointer method, I think I will have to wrap all the objects in another structure (like a pair class) and then return it. 在指针方法中,我认为我必须将所有对象包装在另一个结构(如pair类)中,然后将其返回。 That increases the overhead. 这增加了开销。

However, I do not know if usually one is preferred over the other. 但是,我不知道通常一个人是否比另一个人更可取。 And if there are any function naming conventions in C++ that let the developer know that he is supposed to pass the return object also as an argument. 并且如果C ++中有任何函数命名约定,使开发人员知道他应该将返回对象也作为参数传递。

You could try returning an auto_ptr or shared_ptr. 您可以尝试返回auto_ptr或shared_ptr。 That would eliminate the issues with delete. 这样可以消除删除问题。

The second approach is probably preferable because there is no possibility of a memory leak, in the event you forget to delete the returned pointer. 第二种方法可能更可取,因为在您忘记delete返回的指针的情况下,不会发生内存泄漏。

It's usually good practice to code in such a way that each function or object which allocates heap memory also deallocates that memory. 通常,以这样一种方式进行编码是一种好习惯,即分配堆内存的每个函数或对象也都会释放该内存。 Your first example violates that practice, making it the function caller's responsibility to deallocate the memory. 您的第一个示例违反了这种做法,这使函数调用者有责任重新分配内存。 This makes memory leaks more likely, because now every time the function is called there is another opportunity to forget to delete the returned pointer. 这使内存泄漏的可能性更大,因为现在每次调用该函数时,都有另一个机会忘记删除返回的指针。

You may also want to consider returning the object by value (which will return a copy of the object) in cases where the size of the object is not that large. 在对象的大小不那么大的情况下,您可能还需要考虑按值返回对象(这将返回对象的副本)。 Even though this will require a copy to be created, if the object is not so large it won't impact performance. 即使这需要创建一个副本,但如果对象不是很大,也不会影响性能。 (This method will become a lot more attractive in the future with C++0x move semantics.) (这种方法在将来会随着C ++ 0x move语义变得更具吸引力。)

I think your first option should be returning by value (or perhaps make the constructor compute the members?): 我认为您的第一个选择应该是按值返回(或者让构造函数计算成员?):

Node computeNode()
{
    Node n;
    n.x = abc;
    n.y = xyz;
    return n;
}

This may look inefficient, but it is quite possible that copying is elided with NRVO. 这看起来效率低下,但是很有可能使用NRVO消除了复制。

If the Node needs to be dynamically allocated anyway, you should return the pointer by value (a copy of the pointer): 如果仍然需要动态分配Node,则应按值返回指针(指针的副本):

Node* computeNode();

Otherwise you will be returning a reference to a local variable (pointer). 否则,您将返回对局部变量(指针)的引用。

I prefer using the second approach to send back information (as you said, allows for multiple "returns" without using an extra structure) and generally return an error or a success code . 我更喜欢使用第二种方法发送回信息(如您所说,无需使用额外的结构即可进行多次“返回”),并且通常返回错误或成功代码

Also, I set the purely input arguments as const & to distinguish between the input and output variables. 另外,我将纯输入参数设置为const &以区分输入变量和输出变量。

You can return by value and avoid copies in some situations, by using const references like this : 您可以通过使用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();

The lifetime of the temporary object in computeNode is extended upto the scope of the reference n 临时对象在computeNode中的生存期已扩展到引用n的范围

If the alternatives are really as given, it's not clear why you need a reference/pointer at all; 如果这些替代方案确实是给定的,则不清楚为什么您根本需要引用/指针。 you could also just return by value: 您也可以按值返回:

Node computeNode() {
    // Do some computation before creating a node object.
    Node newNode;
    newNode.member1 = xyz;
    newNode.member2 = abc;
    return newNode;
}

Despite what many people think, this isn't actually very inefficient because the compiler can (and will!) elide most of the unnecessary copies . 尽管有许多人认为,但这实际上并不是很低效,因为编译器可以(并且将!)淘汰大多数不必要的副本

Semantically, this is the solution that you want, unless the node gets stored somewhere else as well and you need to preserve reference identity. 从语义上讲,这是您想要的解决方案,除非节点也存储在其他位置并且您需要保留引用身份。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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