通过引用传递表达式与通过引用传递变量

Passing an expression by reference vs Passing variable by reference

在下面显示的代码中,func(a3) 进入 if 条件并产生输出 "hi"。但是,当函数的参数是表达式时,会观察到不同的行为。

例如func(a1->right)不进入if条件

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

我有两个问题:

  1. 表达式引用 传递给 func 而不是 变量引用 时不同行为的原因?

  2. 将表达式的引用传递给函数的惯用方式是什么。

编辑:gdb 输出

(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 
 = 30 // a3
(gdb) n
19      p->right = node->left;
(gdb) p p->data
 = 10 // a1
(gdb) n
20      if (node->left) {
(gdb) p p->right->data
 = 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
 = (Node *) 0x0
(gdb) 

您已传递对 a1->right 的引用。因此,您对该字段所做的任何更改都会在该函数中看到。 p->right = node->left; 实际上将 a1->right 设置为不同的节点。

在情况 3 中,您传递了对局部变量 ptr 的引用,该变量不会更改,因为它是一个副本。

如果您添加:

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

您会看到您的节点发生了变化。

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

原因是您的程序中存在复杂的逻辑。在这种特殊情况下,当您传递 a3a1->right 时,任一指针指向同一对象,但 func() 本身会修改 a1->right,因此当对 a3 的引用传递时该更改不会影响 node 但当 a1->right 通过时它会影响。请注意区别。

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

按照您的方式传递引用没有问题,问题是数据关系过于复杂。例如,在您的情况下,没有理由通过引用传递此指针。