What is the Stack

beginner c++11 memory

All variables in C++ use a portion of the memory of your computer. C++ has two basic forms of memory: the stack and the heap. The stack is where local variables are stored in memory. Local here means “in the current scope” and a scope is defined as the code between curly braces ({}). Every time a new scope is created C++ uses a portion of the stack to store that scope’s local variables and if it’s a function its parameters and return value. Because C++ has pointers we can print the addresses of stack variables and confirm for ourselves they are using different pieces of memory. Here’s an example of scopes and stack variables:

#include <iostream>

void foo(int a) {
  std::cout << "      foo() Scope\n";
  int b = 4;
  std::cout << "      a: " << a << ", &a: " << &a << "\n";
  std::cout << "      b: " << a << ", &b: " << &b << "\n";
  std::cout << "      leaving foo() Scope\n";
}

int main() {
  std::cout << "Main Scope\n";
  int a = 10;
  std::cout << "a: " << a << ", &a: " << &a << "\n";

  {
    std::cout << "  First Inner Scope\n";
    int b = 20;
    std::cout << "  a: " << a << ", &a: " << &a << "\n";
    std::cout << "  b: " << b << ", &b: " << &b << "\n";

    {
      std::cout << "    Second Inner Scope\n";
      int c = 30;
      std::cout << "    a: " << a << ", &a: " << &a << "\n";
      std::cout << "    b: " << b << ", &b: " << &b << "\n";
      std::cout << "    c: " << a << ", &c: " << &c << "\n";

      foo(a);

      std::cout << "    Leaving Second Inner Scope\n";
    }
      
    std::cout << "  a: " << a << ", &a: " << &a << "\n";
    std::cout << "  b: " << b << ", &b: " << &b << "\n";
    std::cout << "  Leaving First Inner Scope\n";
  }
  std::cout << "a: " << a << ", &a: " << &a << "\n";
  std::cout << "Leaving Main Scope\n";
}
Main Scope
a: 10, &a: 0x7ff7b34465cc
  First Inner Scope
  a: 10, &a: 0x7ff7b34465cc
  b: 20, &b: 0x7ff7b34465c8
    Second Inner Scope
    a: 10, &a: 0x7ff7b34465cc
    b: 20, &b: 0x7ff7b34465c8
    c: 10, &c: 0x7ff7b34465c4
      foo() Scope
      a: 10, &a: 0x7ff7b34465ac
      b: 10, &b: 0x7ff7b34465a8
      leaving foo() Scope
    Leaving Second Inner Scope
  a: 10, &a: 0x7ff7b34465cc
  b: 20, &b: 0x7ff7b34465c8
  Leaving First Inner Scope
a: 10, &a: 0x7ff7b34465cc
Leaving Main Scope

Automatic Memory Management

Explicit management of the stack is not necessary in your program and is automatic in C++. Automatic memory management of scopes and local variables is one of the many things your compiler is doing for you when your code is compiled into a complete program. If you’re familiar with destructors you’ll remember that C++ always calls object destructors when that object is leaving the scope it’s in. That’s because the stack memory of that object is about to be reclaimed and reused for the next scope and so the object must be cleaned up. Here’s an example:

#include <iostream>

class Talker {
public:
  explicit Talker(std::string name) : name_(std::move(name)) {
    std::cout << name_ << " here.\n";
  }
  ~Talker() {
    std::cout <<  name_ << ", signing off.\n";
  }
private:
  std::string name_;
};

int main() {
  std::cout << "Main Scope\n";
  Talker jose("Jose");
  std::cout << "&jose: " << &jose << "\n";

  {
    std::cout << "  First Inner Scope\n";
    Talker nushi("  Nushi");
    std::cout << "  &nushi: " << &nushi<< "\n";
    std::cout << "  Leaving First Inner Scope\n";
  }
  std::cout << "Leaving Main Scope\n";
}
Main Scope
Jose here.
&jose: 0x7ff7bc8575b8
  First Inner Scope
  Nushi here.
  &nushi: 0x7ff7bc857578
  Leaving First Inner Scope
  Nushi, signing off.
Leaving Main Scope
Jose, signing off.

Variable Shadows

When new scopes are created variables from outer scopes can still be used, but they can also be shadowed meaning their names can be reused.

#include <iostream>

int main() {
  int a = 4;
  std::cout << "a: " << a << ", &a: " << &a << "\n";

  {
    // Assign to the same "a" from outer scope
    a = 8;
    std::cout << "  a: " << a << ", &a: " << &a << "\n";

    {
      // *Shadow* the outer scope's "a", create a new "a"
      int a = 12;
      std::cout << "    a: " << a << ", &a: " << &a << "\n";
    }
      
    std::cout << "  a: " << a << ", &a: " << &a << "\n";
  }
  std::cout << "a: " << a << ", &a: " << &a << "\n";
}
a: 4, &a: 0x7ff7b03b95cc
  a: 8, &a: 0x7ff7b03b95cc
    a: 12, &a: 0x7ff7b03b95c8
  a: 8, &a: 0x7ff7b03b95cc
a: 8, &a: 0x7ff7b03b95cc


For more C++ By Example, click here.