A pointer can still hold an address after the object at that address has ceased to exist. An object’s lifetime is the interval of execution during which it can be accessed; referring to it outside that interval is invalid. Lifetime depends on execution, not merely on whether an identifier is visible at a point in the code. section 13.2
The way an object is created determines its storage duration and lifetime:
- Static objects last for the whole program execution. section 13.0 section 13.2
- Ordinary automatic objects last for an execution of their defining block. Each recursive call has its own local instance; variable-length arrays and temporary objects require separate rules. section 13.2.2
- Allocated storage is controlled explicitly through calls such as malloc; thread storage is bound to a thread of execution. section 13.2
TAKEAWAY: Scope and lifetime answer different questions. A local declaration can shadow an outer name without ending the outer object’s lifetime: a pointer obtained earlier can still reach it. section 13.2
A jump over a compound literal
In fgoto(2), goto repeats a statement within its surrounding block. The displayed output first reports unequal pointers with *p equal to 0, then equal pointers with *p equal to 1. Reaching the literal’s definition again does not, in this case, create a separate object for each jump. The automatic object’s lifetime begins on entry to its defining scope, rather than only when execution reaches its definition. section 13.3
Listing 13.3 A contrived example for the use of a compound literal
void fgoto(unsigned n) {
unsigned j = 0;
unsigned* p = nullptr;
unsigned* q;
AGAIN:
if (p) printf("%u: p and q are %s, *p is %u\n",
j,
(q == p) ? "equal" : "unequal",
*p);
q = p; 1
p = &((unsigned){ j, });
++j;
if (j <= n) goto AGAIN;
}
Follow p and q through the jumps to see why revisiting the compound literal differs from entering a new block. section 13.3
A while loop changes that result. Each iteration creates a new instance of a local compound literal, so a pointer retained after the loop cannot be used to access it. Repeating a statement by goto within one surrounding block can leave that block’s object alive until the block ends. The two forms are not interchangeable when an address escapes. section 19.3
size_t* ip = nullptr;
while(something)
ip = &(size_t){ fun() }; /* Life ends with while */
/* Good: resource is released */
printf("i is %d", *ip) /* Bad: object is dead */
The while example marks the post-loop dereference as invalid because the compound literal’s lifetime has ended. section 19.3
size_t* ip = nullptr;
RETRY:
ip = &(size_t){ fun() }; /* Life continues */
if (condition) goto RETRY;
/* Bad: resource is kept */
printf("i is %d", *ip) /* Good: object is alive */
The contrasting goto example keeps the object alive at the later dereference, but also keeps its resources occupied. section 19.3







