Last updated:2026-10-12
C++ Pointers vs References¶
About the Author:¶
Personal WeChat official account:

1. References and Pointers¶
Overview:
| Reference | Pointer |
|---|---|
| Must be initialized | May be left uninitialized |
| Cannot be null | Can be null |
| Cannot change its target | Can change its target |
A reference must be initialized, whereas a pointer may be left uninitialized.
When we define a reference we must give it an initial value, but a pointer does not need one.
A reference cannot be null, whereas a pointer can.
Since a reference cannot be null, we do not need to validate it when using one; with a pointer, however, we must first check whether it is a null pointer, otherwise the program may crash.
void test_p(int* p)
{
if(p != null_ptr) //对p所指对象赋值时需先判断p是否为空指针
*p = 3;
return;
}
void test_r(int& r)
{
r = 3; //由于引用不能为空,所以此处无需判断r的有效性就可以对r直接赋值
return;
}
A reference cannot change its target
A pointer can change what it points to at any time, but a reference can only ever refer to the object it was bound to at initialization and cannot be changed.
int a = 1;
int b = 2;
int &r = a; //初始化引用r指向变量a
int *p = &a; //初始化指针p指向变量a
p = &b; //指针p指向了变量b
r = b; //引用r依然指向a,但a的值变成了b
2. References¶
Lvalue References¶
Ordinary references, which generally represent the identity of an object.
Rvalue References¶
An rvalue reference is a reference that must be bound to an rvalue (a temporary object, an object about to be destroyed); it generally represents the value of an object.
Rvalue references enable move semantics and perfect forwarding, and they serve two main purposes:
- Eliminating unnecessary object copies when two objects interact, saving computation and storage resources and improving efficiency.
- Making it simpler and clearer to define generic functions.
Reference Collapsing¶
X& &,X& &&,X&& &collapse intoX&X&& &&collapses intoX&&
C++ references trade some programmer freedom for greater safety in memory operations and more elegant semantics. For example, the requirement that a reference must be initialized means that when we use one we no longer have to check whether it is null, which keeps the code cleaner and more elegant and avoids pointers flying everywhere. Beyond that scenario, references are also used in the following two situations:
Reference parameters
We generally use const reference parameters for read-only arguments; in this case we both avoid copying the argument and keep the same call syntax as pass-by-value.
void test(const vector<int> &data)
{
//...
}
int main()
{
vector<int> data{1,2,3,4,5,6,7,8};
test(data);
}
Reference return values
C++ lets us overload operators. When overloading certain operators, using a reference return type gives us call syntax identical to the operator's original syntax, preserving the consistency of the operator's semantics. One example is the operator [] — this operator generally needs to return a reference for the result to be correctly modifiable.
vector<int> v(10);
v[5] = 10; //[]操作符返回引用,然后vector对应元素才能被修改
//如果[]操作符不返回引用而是指针的话,赋值语句则需要这样写
*v[5] = 10; //这种书写方式,完全不符合我们对[]调用的认知,容易产生误解
3. The Performance Gap Between Pointers and References¶
Is there a performance gap between pointers and references? To answer this kind of question we need to drop down to the assembly level. Let us first write a test1 function that passes its parameter by pointer:
The assembly code corresponding to this snippet is as follows:
(gdb) disassemble
Dump of assembler code for function test1(int*):
0x0000000000400886 <+0>: push %rbp
0x0000000000400887 <+1>: mov %rsp,%rbp
0x000000000040088a <+4>: mov %rdi,-0x8(%rbp)
=> 0x000000000040088e <+8>: mov -0x8(%rbp),%rax
0x0000000000400892 <+12>: movl $0x3,(%rax)
0x0000000000400898 <+18>: nop
0x0000000000400899 <+19>: pop %rbp
0x000000000040089a <+20>: retq
End of assembler dump.
In the code above, lines 1 and 2 are the parameter-passing and stack-frame setup; line 3 is parameter passing — the first argument of a call is usually placed in the rdi register, and this line writes the value of the rdi register (the value of the pointer p) onto the stack; line 4 writes the value of p from the stack into the rax register; line 5 writes the immediate value 3 into the memory pointed to by the value in the rax register. Note the parentheses around (%rax) here — they are by no means optional: (%rax) and %rax mean completely different things. (%rax) denotes the memory at the address held in the rax register, which is equivalent to *p in C++ code, whereas %rax denotes the rax register itself, equivalent to the value of p in C++ code. That is why the assembly uses (%rax) rather than %rax.
Now let us write the C++ snippet test2, which passes its parameter by reference:
The assembly code corresponding to this snippet is as follows:
(gdb) disassemble
Dump of assembler code for function test2(int&):
0x000000000040089b <+0>: push %rbp
0x000000000040089c <+1>: mov %rsp,%rbp
0x000000000040089f <+4>: mov %rdi,-0x8(%rbp)
=> 0x00000000004008a3 <+8>: mov -0x8(%rbp),%rax
0x00000000004008a7 <+12>: movl $0x3,(%rax)
0x00000000004008ad <+18>: nop
0x00000000004008ae <+19>: pop %rbp
0x00000000004008af <+20>: retq
End of assembler dump.
We find that the assembly for test2 is exactly the same as the assembly for test1, which shows that the C++ compiler compiles pointers and references into exactly the same machine code. So a C++ reference is merely "syntactic sugar" over pointer operations: at the underlying implementation level, the C++ compiler implements the two operations in exactly the same way.
3. Summary¶
C++ introduced references so that, under more restrictive rules of use, they guarantee safety and convenience while keeping the code elegant. Using the right tool in the right situation, references can to some extent avoid the "pointers flying everywhere" situation, which also has a positive effect on program stability. Finally, pointers and references have identical underlying implementations, so there is no need to worry about any performance gap between them.
The above partly references: http://irootlee.com/juicer_pointer_reference/#
Related Topics¶
- C++ Pure Virtual Functions and Abstract Classes | C++那些事
- C++ assert | C++那些事
- C++ Bit Fields | C++那些事
- Implementing C++ Polymorphism in C | C++那些事
- C++ const Constants and Qualifiers | C++那些事
- The Complete C++ const Family | C++那些事
- C++ Dereference Operator * | C++那些事
- C++ Initialization and Assignment | C++那些事
- Ways to Return Multiple Values in C++ | C++那些事
- C++ mutable Keyword | C++那些事