C++ Crash Course: a fast-Paced Introduction



Yüklə 7 Mb.
Pdf görüntüsü
səhifə28/71
tarix20.09.2023
ölçüsü7 Mb.
#145939
1   ...   24   25   26   27   28   29   30   31   ...   71
C Crash Course A Fast-Paced Introduction by Josh Lospinoso

References
Pointers are a crucial feature of C (and by extension most system program-
ming). They enable you to handle large amounts of data efficiently by pass-
ing around data addresses instead of the actual data. Pointers are equally 
crucial to C++, but you have additional safety features available that defend 
against null dereferences and unintentional pointer reassignments.
References are a major improvement to handling pointers. They’re similar 
to pointers, but with some key differences. Syntactically, references differ from 
pointers in two important ways. First, you declare them with 
&
rather than 
*
, as 
Listing 4 illustrates.
struct HolmesIV {
bool is_sentient;
int sense_of_humor_rating;
};
void mannie_service(HolmesIV*); // Takes a pointer to a HolmesIV
void mannie_service(HolmesIV&); // Takes a reference to a HolmesIV
Listing 4: Code illustrating how to declare functions taking pointers and references
Second, you interact with members using the dot operator 
.
rather than 
the arrow operator 
->
, as Listing 5 illustrates.
void make_sentient(HolmesIV* mike) {
mike->is_sentient = true;
}
void make_sentient(HolmesIV& mike) {
mike.is_sentient = true;
}
Listing 5: A program illustrating the use of the dot and arrow operators


An Overture to C Programmers
xli
Under the hood, references are equivalent to pointers because they’re 
also a zero-overhead abstraction. The compiler produces similar code. To 
illustrate this, consider the results of compiling the 
make_sentient
functions 
on GCC 8.3 targeting x86-64 with 
-O2
. Listing 6 contains the assembly gen-
erated by compiling Listing 5.
make_sentient(HolmesIV*):
mov BYTE PTR [rdi], 1
ret
make_sentient(HolmesIV&):
mov BYTE PTR [rdi], 1
ret
Listing 6: The assembly generated from compiling Listing 5
However, at compile time, references provide some safety over raw 
pointers because, generally speaking, they cannot be null.
With pointers, you might add a 
nullptr
check to be safe. For example, 
you might add a check to 
make_sentient
, as in Listing 7.
void make_sentient(HolmesIV* mike) {
if(mike == nullptr) return;
mike->is_sentient = true;
}
Listing 7: A refactor of 
make_sentient
 from Listing 5 so it performs a 
nullptr
 check
Such a check is unnecessary when taking a reference; however, this 
doesn’t mean that references are always valid. Consider the following function:
HolmesIV& not_dinkum() {
HolmesIV mike;
return mike;
}
The 
not_dinkum
function returns a reference, which is guaranteed to be 
non-null. But it’s pointing to garbage memory (probably in the returned-
from stack frame of 
not_dinkum
). You must never do this. The result will 
be utter misery, also known as undefined runtime behavior: it might crash, it 
might give you an error, or it might do something completely unexpected.
One other safety feature of references is that they can’t be reseated. In 
other words, once a reference is initialized, it can’t be changed to point to 
another memory address, as Listing 8 shows.
int main() {
int a = 42;
int& a_ref = a; 
u
int b = 100;
a_ref = b; 
v
}
Listing 8: A program illustrating that references cannot be reseated


xlii
An Overture to C Programmers
You declare 
a_ref
as a reference to 
int a
u
. There is no way to reseat 
a_ref
to point to another 
int
. You might try to reseat 
a
with 
operator=
v
, but 
this actually sets the value of 
a
to the value of 
b
instead of setting 
a_ref
to 
reference 
b.
After the snippet is run both 
a
and 
b
are equal to 
100
, and 
a_ref
still points to 
a
. Listing 9 contains equivalent code using pointers instead.
int main() {
int a = 42;
int* a_ptr = &a; 
u
int b = 100;
*a_ptr = b; 
v
}
Listing 9: An equivalent program to Listing 8 using pointers
Here, you declare the pointer with a 
*
instead of a 
&
u
. You assign the 
value of 
b
to the memory pointed to by 
a_ptr
v
. With references, you don’t 
need any decoration on the left side of the equal sign. But if you omit the 
*
in 
*a_ptr
, the compiler would complain that you’re trying to assign an 
int
to 
a pointer type.
References are just pointers with extra safety precautions and a sprinkle 
of syntactic sugar. When you put a reference on the left side of an equal sign, 
you’re setting the pointed-to value equal to the right side of the equal sign.

Yüklə 7 Mb.

Dostları ilə paylaş:
1   ...   24   25   26   27   28   29   30   31   ...   71




Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©azkurs.org 2024
rəhbərliyinə müraciət

gir | qeydiyyatdan keç
    Ana səhifə


yükləyin