liveBook · Manning

Undefined behavior

As explained in C++ Concurrency in Action, Second Edition

Undefined behavior is program behavior for which the C++ language standard imposes no requirements.

Undefined behavior is behavior for which the C++ standard imposes no requirements. Once a program has it, the behavior of the whole application is unconstrained. section 5.1.2

Common routes to undefined behavior and an important limit:

  • A data race occurs when accesses to one memory location in separate threads lack enforced ordering, at least one access is a write, and at least one access is non-atomic. section 5.1.2
  • Atomic access can avoid undefined behavior for a raced memory location, though it does not specify which atomic operation occurs first. section 5.1.2
  • With std::execution::parallel_policy, a call that permits data races is undefined behavior even if the implementation happens to use only one thread. section 10.2.3
  • A lock-free stack pop that dereferences a null head also causes undefined behavior. section 7.2.1

A pointer passed to a detached thread

If a thread receives a pointer to a local character buffer and the function returns before the new thread converts it to std::string, the pointer may outlive the buffer. Constructing the string before passing the argument avoids this timing problem. section 2.2

std::for_each(std::execution::par,v.begin(),v.end(),
    [&](int& x){ x=++count; });


!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":0,\"ch\":14},{\"line\":0,\"ch\":33}]]"}
!@%STYLE%@!

Each parallel invocation increments shared count without synchronization. Making count atomic or protecting it with a mutex can define access, though synchronization may serialize the calls. section 10.2.3

How C++ Concurrency in Action, Second Edition covers it

How deep it goes
Defines the consequence and explains data-race and parallel-policy cases, without surveying undefined behavior exhaustively.
Examples
Uses a detached thread's local buffer and a lock-free stack pop on an empty stack as examples.
What you can do after
Diagnose data-race and parallel-policy cases, and identify atomic or mutex synchronization as ways to define shared access.
How it connects
Connects it to data races, atomic operations, synchronization, and parallel execution policies.

Also explained in

Compare how 7 books explain undefined behavior →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of C++ Concurrency in Action, Second Edition. The section links point to the parts of the book it draws on.