Aravind Nujella
Aravind Nujella

Reputation: 103

Passing an expression by reference vs Passing variable by reference

In the code shown below, func(a3) enters the if condition and produces output "hi". However, different behavior is observed when the parameter to the function is an expression.

For example, func(a1->right) doesn't enter the if condition.

#include <iostream>
using namespace std;
class Node {
   public:
    int data;
    Node *left, *right, *parent;

   public:
    Node(int data) : data(data) {
        left = nullptr;
        right = nullptr;
        parent = nullptr;
    }
    ~Node() {}
};
void func(Node*& node) {
    Node* p = node->parent;
    p->right = node->left;
    if (node->left) {
        cout << "hi\n";
        node->left->parent = p;
    }
    node->parent = p->parent;
}
int main() {
    Node* a1 = new Node(10);
    Node* a2 = new Node(20);
    Node* a3 = new Node(30);
    Node* a4 = new Node(40);
    Node* a5 = new Node(50);
    a1->left = a2; a2->parent = a1;
    a1->right = a3; a3->parent = a1;
    a3->left = a4; a4->parent = a3;
    a3->right = a5; a5->parent = a3;
    /*
         a1
       /   \
     a2     a3
           /  \
           a4   a5
     */

    /* Case 1: prints hi */
    func(a3);

    /* Case 2: doesn't print hi */
    // func(a1->right);


    /* Case 3: prints hi */
    // Node* ptr = a1->right;
    // func(ptr);
}

I have two questions:

  1. Reason for different behavior when reference of expression is passed to func as opposed to reference of a variable?

  2. What is idiomatic way of passing reference of an expression to a function.

Edit: gdb output

(gdb) b 17
Breakpoint 1 at 0x555555554856: file pointer_ref.cpp, line 17.
(gdb) r
Starting program: /home/a.out 

Breakpoint 1, func (node=@0x555555767e80: 0x555555767ed0) at pointer_ref.cpp:18
18      Node* p = node->parent;
(gdb) p node->data 
$1 = 30 // a3
(gdb) n
19      p->right = node->left;
(gdb) p p->data
$2 = 10 // a1
(gdb) n
20      if (node->left) {
(gdb) p p->right->data
$3 = 40 // a4
**(gdb) p node->left->data
Cannot access memory at address 0x0**
// ^^^ This seems to be the problem location
// After changing p->right to node->left,
// somehow, node->left becomes null 
(gdb) p node->left
$4 = (Node *) 0x0
(gdb) 

Upvotes: 0

Views: 198

Answers (2)

Slava
Slava

Reputation: 44278

Reason for different behavior when reference of expression is passed to func as opposed to reference of a variable?

Reason is the convoluted logic you have in your program. In this particular case when you either pass a3 or a1->right either pointer points to the same object, but func() itself modifies a1->right so when reference to a3 passed that changes does not affect node but when a1->right passed it does. Hense the difference.

What is idiomatic way of passing reference of an expression to a function.

There is no problem of passing reference the way you do, problem is overcomplicated data relationship. For example in your case there is no reason to pass this pointer by reference.

Upvotes: 0

rkapl
rkapl

Reputation: 990

You have passed reference to a1->right. So any changes you make to that field are seen in that function. The p->right = node->left; actually sets a1->right to a different node.

In the case 3, you pass reference to a local variable ptr, which does not get changed, since it is a copy.

If you add:

    cout << "node was " << node << std::endl;
    p->right = node->left;
    cout << "node is " << node << std::endl;

You will see that your node changes.

Upvotes: 1

Related Questions