简答
除非您希望修改原始指针本身,否则通过引用指针而不是指针传递没有任何好处。
长答案
根据您提出问题的方式,以及您对 cmets 的第一次回复,您对指针和引用的实际含义存在根本性的误解。与您似乎相信的相反,它们本身并不是物体。
让我们回到基本原理。
为了存储数据,我们可以访问内存中的两个主要区域,堆栈内存和堆内存。
当我们声明变量时,我们在堆栈内存中分配了空间,我们可以通过使用变量名来访问数据。当变量超出范围时,内存会自动释放。
void myFunction() {
MyClass instance; // allocated in Stack memory
instance.doSomething();
} // instance gets automatically de-allocated here
最大的问题是堆栈内存的数量与正常程序的需求相比极为有限,而且您经常需要数据在某些范围之外持续存在这一事实,因此在堆栈内存中创建大型类的实例通常是一个坏主意。这就是堆变得有用的地方。
不幸的是,使用堆内存,您需要接管内存分配的生命周期。您也无法直接访问堆内存中的数据,您需要一种垫脚石才能到达那里。您必须明确要求操作系统分配内存,然后在完成后明确告诉它取消分配内存。 C++ 为此提供了两个运算符:new 和 delete。
void myFunction(){
MyClass *instance = new MyClass(); // ask OS for memory from heap
instance->doSomething();
delete instance; // tell OS that you don't need the heap memory anymore
}
您似乎清楚地理解,在这种情况下,实例称为pointer。您似乎没有意识到指针不是对象本身的实例,它是对象的“垫脚石”。指针的目的是保存该内存地址,这样我们就不会丢失它,并使我们能够通过取消引用内存位置来访问该内存。
在 C++ 中有两种方法:要么取消引用整个指针,然后像访问堆栈上的对象一样访问对象的成员;或者,您将使用 Member Dereferencing 运算符并使用它访问成员。
void myFunction(){
MyClass *instance = new MyClass();
(*instance).doSomething(); // older-style dereference-then-member-access
instance->doSomethingElse(); // newer-style using member dereference operator
}
指针本身只是整数的特殊实例。它们包含的值是您分配对象的堆内存中的内存地址。它们的大小取决于您编译的平台(通常是 32 位或 64 位),因此传递它们并不比传递整数更昂贵。
我怎么强调指针变量不是对象本身,它们被分配在堆栈内存中并且当它们超出范围时的行为与任何其他堆栈变量完全一样。
void myFunction() {
MyClass *instance = new MyClass(); // pointer-sized integer of type 'pointer-to-MyClass' created in Stack memory
instance->doSomething();
} // instance is automatically de-allocated when going out of scope.
// Oops! We didn't explicitly de-allocate the object that 'instance' was pointing to
// so we've lost knowledge of it's memory location. It is still allocated in Heap
// memory but we have no idea where anymore so that memory is now 'leaked'
现在,因为在底层,指针只不过是特殊用途的整数,传递它们并不比传递任何其他类型的整数更昂贵。
void myFunction(){
MyClass *instance = new MyClass(); // 'instance' is allocated on the Stack, and assigned memory location of new Heap allocation
instance->doSomething();
AnotherFunction(instance);
delete instance; // Heap memory pointed to is explicitly de-allocated
} // 'instance' is automatically de-allocated on Stack
void anotherFunction(MyClass *inst){ // 'inst' is a new pointer-to-MyClass on the Stack with a copy of the memory location passed in
inst->doSomethingElse();
} // 'inst' is automatically de-allocted
到目前为止,我还没有提到引用,因为它们与指针大体上相同。它们也只是底层的整数,但它们通过使成员访问语法与堆栈变量的语法相同来简化使用。与普通指针不同,引用必须使用有效的内存位置进行初始化,并且该位置不能更改。
以下功能等效:
MyClass &instance
MyClass * const instance
对指针的引用是双重间接的,它们本质上是指向指针的指针,如果您希望能够操作,不仅是堆对象,还包括包含指向该堆对象的内存位置的指针。
void myFunction(){
QString *str = new QString("First string"); // str is allocated in Stack memory and assigned the memory location to a new QString object allocated in Heap memory
substituteString(str);
delete str; // de-allocate the memory of QString("Second String"). 'str' now points to an invalid memory location
} // str is de-allocated automatically from Stack memory
void substituteString(QString *&externalString){ // 'externalString' is allocated in Stack memory and contains memory location of 'str' from MyFunction()
delete externalString; // de-allocate the Heap memory of QString("First string"). 'str' now points to an invalid location
externalString = new QString("Second string"); // Allocate new Heap memory for a new QString object. 'str' in MyFunction() now points to this new location
} // externalString is de-allocated automatically from Stack memory
如果我已经清楚地解释了自己,并且到目前为止您一直关注我,那么您现在应该明白,在您的情况下,当您将指向 QAction 的指针传递给函数时,您并没有复制 QAction对象,您只是将指针复制到该内存位置。由于指针只是底层的整数,因此您只是复制大小为 32 位或 64 位的东西(取决于您的项目设置),并将其更改为引用指针绝对没有区别。