📖
Go C++
  • Introduction
  • Chapter 1: What You Must Know First
    • Virtual Address Space of Process: Memory Partition and Layout
    • Function Call: Stack Frame
    • Program Compiling and Linking
  • Chapter 2: C++ Basics Improvement
    • Default Parameters
    • Inline Function
    • Function Overloading
    • new and delete
    • const and Pointers
    • References in Detail
  • Chapter 3: Object-Oriented Principles
  • Class and Object
  • Constructor and Destructor
  • Shallow Copy and Deep Copy
  • Initializer List
  • Various Member Functions
  • Pointer to Class Members
  • Chapter 4: Template Programming
  • Function Templates
  • Class Templates
  • Memory Allocators
  • Chapter 5: Operator Overloading
    • Operator Overloading
    • Introduction to Iterators
    • Issues of Iterator Invalidation
    • More about new and delete
    • Overloading of new and delete: Object Pool
  • Chapter 6: Inheritance and Polymorphism
    • Look inside Inheritance
    • More about Inheritance
    • Virtual Functions, Static Binding and Dynamic Binding
    • More about Virtual Functions
    • Understanding Polymorphism
    • Abstract Classes
    • Frequently Asked Interview Questions: Polymorphism
  • Chapter 7: Multiple Inheritance
    • Virtual Inheritance and Virtual Base Classes
    • Diamond Problem
    • Four Kinds of Type Conversions
  • Chapter 8: Standard Template Library
    • Sequence Containers
    • Container Adaptors
    • Associative Containers
    • More about Iterators
    • Function Objects
    • Generic Algorithms, Binders and Lambda Expressions
  • Chapter 9: Object Optimization
    • Behind the Object
    • Optimizing Objects in Functions
    • Member Functions with Rvalue References
    • Move Semantics and Perfect Forwarding
  • Chapter 10: Smart Pointers
    • Smart Pointers
    • Smart Pointers without Reference Counting
    • Smart Pointers with Reference Counting
    • Custom Deleters
  • Chapter 11: Function Objects and Binders
    • More about Binders
    • Introduction to std::function
    • Template Specialization and Argument Deduction
    • More about std::function
    • std::bind(): A Simple Thread Pool
    • More about Lambda Expressions
  • Chapter 12: Multithreading
    • Important Features in C++11
    • Multithreaded Programming with std::thread
    • Mutual Exclusion
    • Producer-Consumer Problem
    • Atomic Operations
    • Thread Visibility and volatile
  • Chapter 13: Design Patterns
    • Singleton Pattern
    • Factory Pattern
    • Proxy Pattern
    • Decorator Pattern
    • Adapter Pattern
    • Observer Pattern
Powered by GitBook
On this page
  • References and Pointers
  • Rvalue References
  • const, Pointers and References

Was this helpful?

  1. Chapter 2: C++ Basics Improvement

References in Detail

References and Pointers

A variable can be declared as reference with an & in the declaration. When a variable is declared as reference, it is an alias of an existing variable. Alias means that a variable and its reference can be regarded as the same thing.

int main() {
    int a = 10;
    int *p = &a;
    int &b = a;
    cout << b << endl;  // 10
    return 0;
}

Declaring a pointer variable and a reference variable has the same underlying instructions. Both two approaches get the memory address of the existing variable and stores into the declared variable. Similarly, the assembly commands for modifying the value of a memory address through reference or through pointer dereference, are also the same.

*p = 20;
cout << a << " " << *p << " " << b << endl; // 20 20 20
b = 30;
cout << a << " " << *p << " " << b << endl; // 30 30 30

Unlike pointer which can be declared without initialization or as a nullptr, a reference variable must be initialized with an existing variable when it is declared. In this way, a reference is safer than a pointer since it can't be NULL.

int &q; // ERROR

Besides, these is no multi-level references as pointer does.

Reference plays an important role, especially as function parameters. In the following case, we write a swap function which takes two arguments and swap them. We can make this in using pointers as parameters and pass addresses of arguments inside, but reference makes it in a easier way.

int swap(int &x, int &y) {
    int temp = x;
    x = y;
    y = temp;
}
​
int main() {
    int a = 10;
    int b = 20;
    swap(a, b);
    cout << "a: " << a << "b: " << b << endl;
}

The way we declare reference to an array in kind tricky. We need to add brackets outside the reference variable, which states the priority, and then states the array size with square brackets. It is similar to declaring an array instead of declaring a pointer, since reference is the alias of another variable.

int main() {
    int array[5] = {};
    int *p = array;
    int (&q)[5] = array; 
    
    cout << sizeof(array) << endl;  // 20
    cout << sizeof(p) << endl;  // 4
    cout << sizeof(q) << endl;  // 20
    return 0;
}

In the above case, the pointer has a size of 4 bytes, and reference has a size of 20 bytes, which is the same as the original array.

Rvalue References

All the cases we've seen now is references of Lvalues. A Lvalue is a type of value that can appears at the left of operator =. It has a variable name and a memory address that can be modified. On the contrary, a Rvalue doesn't have a variable name nor a memory address. It can only appears at the right of operator =. We cannot declare a normal reference of a Rvalue.

int main() {
    int a = 10; // a is a Lvalue
    int &b = a;
    int &c = 20;    // ERROR: 20 a Rvalue
    return 0;
}

C++11 introduced many features, one of them is Rvalue references. With two & symbols, we can declare a reference of a constant.

int &&c = 20;

But how can we make a reference to a Rvalue since it doesn't have a memory address? The assembly commands shows the magic. When declaring a Rvalue reference, the compiler creates a temporary variable to store the value of the constant, and then assign the address of that temporary variable to the reference variable.

mov dword ptr [ebp-30h],14h
lea eax,[ebp-30h]
mov dword ptr [c],eax

Alternatively, we can use const to declare a Rvalue reference as well.

const int &c = 20;

Notice that a Rvalue reference is a Lvalue itself, which means that only Lvalue references can be used to refer to it.

int &d = c;
int &&e = c;    // ERROR

const, Pointers and References

Now let's take a look at the following code. Is this code able to be complied or not?

int main() {
    int a = 10;
    int *p = &a;
    const int *&q = p;
    return 0;
}

It seems confusing, but we can convert the reference to a pointer to make it clearer. Notice that int &a = b has the same function as int *p = &b, so the code above can be converted into follows:

int a = 10;
int *p = &a;
const int **q = &p; // ERROR

Now the problem is clear since we already discuss about const and double pointers. The code above actually convert a type of int ** into const int **, which is invalid.

See the post "const and Pointers" if you forget it.

Previousconst and PointersNextClass and Object

Last updated 4 years ago

Was this helpful?