int x for this variable the compiler needs to know

  • when to create memory for it
  • when to destroy it aka how long does it live
  • does another .cpp file refer to this same one
  • are per thread copies

The default scope boundaries are commonly known, eccentrics are harder.

automatic storage duration

This is the default, scope bound duration. Memory is usually allocated on the stack frame for these.

static

static couples tightly with the declaration and behavior varies on where it is declared.

  1. block scope

static storage duration aka lifetime becomes program execution.

void f() {
    static int x = 0;
    ++x;
}
  1. namespace scope

A namespace scoped variable already has static storage duration; so what will static do?

What is internal vs external linkage?

It answers whether the same “qualified name” = namespace + name appearing in different translation units or scopes refers to the same object.

static scross namespaces

This table summarises it cleanly

a.cppb.cppLinkageSame entity?Valid?
static int x = 10;static int x = 20;internal / internalNoYes
static int x = 10;int x = 20;internal / externalNoYes
int x = 10;int x = 20;external / externalYesNo — two definitions

static across blocks

Namespace scopeBlock scopeNamespace x linkageBlock x linkageSame entity?Valid?
static int x = 10;static int x = 20;internalnoneNoYes
static int x = 10;int x = 20;internalnoneNoYes
int x = 10;static int x = 20;externalnoneNoYes
int x = 10;int x = 20;externalnoneNoYes

extern

extern can be treated simply as just a “don’t define storage for it, it’ll be made available from someplace else”

Across translation units but same namespace

a.cppb.cppSame entity?Valid?Meaning
int x = 10;extern int x;YesYesb.cpp refers to a.cpp’s x
extern int x;extern int x;Intended same external entityOnly if defined somewhereNeither line defines x
static int x = 10;extern int x;NoYes but b needs defined somewherea.cpp’s x is internal; b.cpp cannot reach it

Across scopes

Namespace scopeBlock scopeSame entity?Result
int x = 10;extern int x;Yesblock extern redeclares the namespace x
static int x = 10;extern int x;Yesblock extern redeclares the existing internal-linkage x
extern int x;static int x = 20;Noblock static x creates a new local object and hides the namespace x

This last one is a bit special as in this case x is not given an external linkage.

But in general, this model that static gives internal linkage + full lifetime while external gives external linkage but needs it define from somewhere else will be a correct model in most cases

thread local

This’ll create one separate instance per thread. I’m skipping context where this is combined with static and extern ( yes,that’s possible which might seems trange because now we are combining modifiers )

mutable

This is not really a storage class specifier, all it says is that even if the parent object is const this can be modified.

struct A
{
    mutable int x;
};
 
const A a;
 
a.x = 5;      // allowed

Some deleted ones

Historically we had an auto for automatic storage and a register to hint that a value is to be kept in register as it’ll be heaviy used.