lifetime and references

object

sizeof(name)
alignof(name)
.................
decltype(name)
name
#name
.................
size
aligment
storage class
type
value
name
lifetime
(different than typeid(name))
(optional)
(may be undefined)

Scope

Scope (Name Validity)

Declaration point

Scope end

Scope

Block scope

Function scope

Function parameter scope

Namespace scope

Class scope

Enumeration scope

Template parameter scope

void f()
{
  {
    int x;
    int y;
  }
}

(labels only)

void f(int n)
{

}
namespace ns {
  void f();
  namespace {
    void g();
  }
  inline namespace sub {
    void h();
  }
}

namespace ns {
}

(global namespace / global scope)

name lookup

int n;

void f(int n)
{
  if (n > 5)
  {
    int n = 3;
    n = 5;
  }
}
#include <iostream>

void print(int n)
{
  std::cout << n << std::endl;
}

Unqualified name lookup

Qualified name lookup

name lookup

Qualified

UN

{
  {
    {
      {
        x = 3;
      }
    }
  }
}
namespace ns
{
  struct X{};
  void f(X);
}

void f()
{
  ns::X x;
  f(x);
}

name lookup

Qualified

UN

Argument dependent lookup (ADL)

name lookup

Qualified

namespace n1
{
  namespace n2::n3
  {
    namespace n4
    {
      namespace
      {
        inline namespace n
        {
          void f();
        }
      }
    }
  }
}

::n1::n2::n3::n4::f();

name lookup

Qualified

object

lifetime

Scope

name

 

pointers

(addresses)

Prototype

Address operator

Dereference operator

Member access operator

Type*
&object
*pointer
pointer->member
struct type
{
  int member1;
  bool member2;
}

type object = {1, true};

type* obj_ptr = &object;
(*obj_ptr) = {0, false};
obj_ptr->member12 = true;

pointers

dangling

int* f()
{
  int x = 5;
  return &x;
}

void g()
{
  int* ptr = f();
  z = *ptr; // UB
}
int x = 2;
int* x_ptr = &x;
(*x_ptr) = 5;

int y = 5;
x_ptr = &y;

x_ptr = nullptr;
int x = 2;
int& x_ref = x;
x_ref = 5;

int y;
x_ref = y; // x == y cannot rebind

// no 'null reference'

pointers

references

Taking parameters by value or by reference

1.

value

reference

void foo(int x)
{
  ++x;
}

int main()
{
  int n = 3;
  foo(3);
  int m = n;
}

2.

void foo(int& x)
{
  ++x;
}

int main()
{
  int n = 3;
  foo(3);
  int m = n;
}

Taking parameters by value or by reference

1.

value

reference

void foo(int x)
{
  ++x;
}

int main()
{
  int n = 3;
  foo(3);
  int m = n;
  // m == 3
}

2.

int foo(int& x)
{
  ++x;
}

int main()
{
  int n = 3;
  foo(3);
  int m = n;
}

Taking parameters by value or by reference

value

reference

2.

void foo(int& x)
{
  ++x;
}

int main()
{
  int n = 3;
  foo(3);
  int m = n;
}

1.

void foo(int x)
{
  ++x;
}

int main()
{
  int n = 3;
  foo(3);
  int m = n;
  // m == 3
}
int foo(int& x)
{
  ++x;
}

int main()
{
  int n = 3;
  foo(3);
  int m = n;
}

Taking parameters by value or by reference

value

reference

2.

void foo(int& x)
{
  ++x;
}

int main()
{
  int n = 3;
  foo(3);
  int m = n;
  // m == 4
}

1.

void foo(int x)
{
  ++x;
}

int main()
{
  int n = 3;
  foo(3);
  int m = n;
  // m == 3
}
int foo(int& x)
{
  ++x;
}

int main()
{
  int n = 3;
  foo(3);
  int m = n;
}

Taking parameters by value or by reference

value

reference

2.

void foo(int& x)
{
  ++x;
}

int main()
{
  int n = 3;
  foo(3);
  int m = n;
  // m == 4
}

1.

void foo(int x)
{
  ++x;
}

int main()
{
  int n = 3;
  foo(3);
  int m = n;
  // m == 3
}
int foo(int& x)
{
  ++x;
}

int main()
{
  int n = 3;
  foo(3);
  int m = n;
}

1.1.

void foo(int a[])
{
  a[0] = 1;
}

int main()
{
  int a[1] = {3};
  foo(a);
  int m = a[0];
  // m == 1
}

HOW TO Take constants as parameters?

Constants

parameters

#include <iostream>

int countChars(char str[], int length, char c) {
  int result = 0;
  for (int i = 0; i < length; ++i) {
    if (str[i] == c) {
      ++result;
    }
  }
  return result;
}

int main() {
  std::cout << countChars("Hello World", 11, 'e');
}

HOW TO Take constants as parameters?

Constants

parameters

#include <iostream>

int countChars(char* str, int length, char c) {
  int result = 0;
  for (int i = 0; i < length; ++i) {
    if (str[i] == c) {
      ++result;
    }
  }
  return result;
}

int main() {
  std::cout << countChars("Hello World", 11, 'e');
}

HOW TO Take constants as parameters?

Constants

parameters

Const

const int x = 4;
x = 3; // error
int*
int* const
const int*
const int* const

const pointers

int&
const int&

const references

HOW TO Take constants as parameters?

Constants

parameters

#include <iostream>

int countChars(const char* str, int length, char c) {
  int result = 0;
  for (int i = 0; i < length; ++i) {
    if (str[i] == c) {
      ++result;
    }
  }
  return result;
}

int main() {
  std::cout << countChars("Hello World", 11, 'e');
}

HOW TO Take strings as parameters?

strings

parameters

#include <iostream>
#include <string_view> // C++17

int countChars(const std::string_view s, char c) {
  int result = 0;
  for (int i = 0; i < s.size(); ++i) {
    if (s[i] == c) {
      ++result;
    }
  }
  return result;
}

int main() {
  std::cout << countChars("Hello World", 'e');
}

references

r-value references (          )

l-value references (        )

forwarding references (          )

Type&
Type&&
Type&&
         int x = 3, 
             y = 8;
 std::string s = "Hello"
std::string s2 = std::to_string(x);
         int z = x + y;

references

r-value

Temporary lifetime extension

Function overload selection

std::string s = "Hello";

//std::string& s_ref = s + " World";
std::string&& s_rref = s + " World";

s_rref += "!\n";
void std::string f(const std::string&);
void std::string f(std::string&&);

std::string s = "Hello";

f(s);
f(s + " World!\n");
  • move constructors
  • move assignment operators
  • move aware functions
    • std::vector::push_back

lifetime and references