Home C++ 和 Python 引用的区别
Post
Cancel

C++ 和 Python 引用的区别

C++ 和 Python 中的引用的区别

一、引言

今天读代码的时候,看到了这样一段:

1
2
graphs = [torch.cuda.CUDAGraph() for _ in range(4)]
tensors = sequential_V_exec(models, caches, graphs)

我对 Python 的掌握称不上熟练,读到这里时突然恍惚了:

传入函数 sequential_V_exec 的 graphs,在函数内被修改后,这种修改能否保留到函数返回后?

或者更简洁地说:Python 的函数传参,是值传递还是引用传递

查阅资料发现,Python 的传参,与值传递(pass by value)以及引用传递(pass by reference)都不完全一样,可以被理解为是「对象引用传递(pass by object reference)」。这意味着,当你将一个变量作为参数传递给函数时,实际上传递的是对该变量所引用对象的引用,而不是变量本身的副本。

听上去更像是引用传递,但还是有区别的。

不过最开始的问题解决了:修改能否保留到函数返回后?能。

二、函数内发生修改?

2.1 Python 的参数传递

在上面的例子中,graphs 是一个列表,被作为参数传递到了函数 sequential_V_exec 内,如果在这个函数内部对其进行了修改,例如,添加、删除或修改列表中的元素,这些修改会反映到函数外部的 graphs 变量上。

这是因为,函数内外的 graphs 变量引用的是同一个列表对象。

截止到这里,它的表现还与引用传递相同。

但是,如果在函数内部将 graphs 重新绑定到一个新的列表上,这个改变不会影响到外部的 graphs 变量。

因为这样做仅仅改变了函数内部的 graphs 变量所引用的对象,而外部的 graphs 变量仍然引用原来的列表

举例来说:

  • 如果 sequential_V_exec 函数内部执行了如 graphs.append(another_graph) 这样的操作,那么外部的 graphs 列表也会包含这个新增的元素。
  • 如果 sequential_V_exec 函数内部执行了如 graphs = [some_other_graph] 这样的操作,那么这个改变不会影响到外部的 graphs 变量,因为这仅仅改变了函数内部的 graphs 变量所引用的对象。

2.2 C++ 的引用传递

C++ 中的引用传递(pass-by-reference)与 Python 中的对象引用传递有相似之处,但也有其特定的语法和规则。

在 C++ 中,引用作为参数传递,意味着函数接收的是原始变量的直接引用,同样不是其副本。因此,函数内对引用参数的任何修改都会直接反映到外部的原始变量上。

但是,C++ 的引用一旦被初始化后,就无法被改变去引用另一个对象。

补充:

引用在 C++ 中相当于原始变量的别名,对引用的任何操作实际上都是直接作用于原始变量上的。对引用求地址,就是对目标变量求地址。

引用在定义上是说引用不占据任何内存空间,但是编译器在一般将其实现为 const 指针,即指向位置不可变的指针,所以引用实际上与一般指针同样占用内存。

sizeof 指针对象和引用对象的意义不一样。sizeof 引用得到的是所指向的变量的大小,而 sizeof 指针是对象地址的大小。

那么,如果我在函数内部,尝试改变引用指向呢?

比如这段代码:

1
2
3
4
5
6
7
8
9
10
void attemptToRebindReference(std::vector<int>& vec) {
    std::vector<int> newVec = {10, 20, 30};
    vec = newVec; // 尝试改变引用指向
}

int main() {
    std::vector<int> originalVec = {1, 2, 3}; 
    attemptToRebindReference(originalVec);    
    return 0;
}

在函数调用后,输出 originalVec,结果是什么呢?

C++-image1

发现,originalVec 的值确实改变了。

类似功能的代码在 Python 中运行,originalVec 是不会发生改变的,在 C++ 中,vec = newVec; 这行代码不会改变 vec 引用的指向,而是将 newVec 的内容复制vec 引用的原始对象 originalVec 中。引用的指向始终未变,始终指向 originalVec

在 C++ 中对引用重新赋值,相当于对原对象赋值,而在 Python 中则是更改引用的对象。

This post is licensed under CC BY 4.0 by the author.