Skip to content

4Developers 2019: Initialisation in modern C++ [ENG], Timur Doumler

Timur Doumler

CommunityPROIDEA Events46 minOpen on YouTube ↗

Presenters detail vulnerability discovery and exploitation in 4Developers 2019: Initialisation in modern C++ [ENG], Timur Doumler.

Summary

## Overview Timur Doumler discusses the many ways to initialize variables in modern C++, a topic he notes is remarkably complex for such a basic operation. He covers initialization in C++17 and previews changes in C++20, providing recommendations for practical usage.

## Key Topics Covered

**Default Initialization:** Not initializing a variable at all. This results in undefined behavior for local variables and uninitialized class members. Doumler emphasizes always using default member initializers in class definitions to avoid this pitfall.

**Copy Initialization:** Using the equals sign (e.g., `int i = 2`). Also occurs when passing by value or returning by value. Performs implicit type conversion if needed.

**Aggregate Initialization:** Uses brace syntax for arrays and simple struct types. Allows omitting initializers, which get zero-initialized. Features "brace elision" for nested aggregates.

**Direct Initialization:** Uses parentheses syntax (e.g., `widget w(1)`). Uses normal overload resolution rather than conversion sequences. Differs from copy initialization, particularly with explicit constructors.

**Value Initialization:** Empty parentheses (e.g., `int i()`). Calls the default constructor if user-provided; otherwise zero-initializes. Includes subtle distinction between user-provided and user-defined constructors that affects behavior.

**List Initialization (C++11):** Uses braces for "uniform initialization." Creates initializer_list objects, which are problematic in several ways: difficult to reason about constructor selection, doesn't work well in templated code, incompatible with macros, and problematic interactions with move-only types.

## Technical Details

Doumler explains specific pitfalls with list initialization, including: - Vector initialization with `vector<int> v{3}` versus `vector<int> v(3)` producing different results - String initialization `string s{48, 'a'}` producing unexpected output due to character conversion - Undefined behavior with nested braces like `vector<string> v{{"a"}}` - Narrowing conversion prevention with braces

He discusses the "most vexing parse" problem where `widget w()` declares a function rather than calling a constructor.

## C++20 Features Preview

**Designated Initializers:** Members can be initialized by name using dot notation (e.g., `.member = value`), similar to C99 feature.

**Direct Initialization of Aggregates:** C++20 allows using parentheses syntax for aggregate types, avoiding many list initialization problems and enabling use in templated code and macros.

## Recommendations

Doumler's personal style recommendations: - Always use default member initializers in classes (first recommendation) - Use `auto` for variables in function scope to prevent uninitialized variables - Use copy initialization syntax for simple values - Use braces only when necessary (containers, aggregates, temporaries) - Use parentheses for constructor calls with direct initialization for clarity and predictable overload resolution - Avoid braces for constructor calls due to complexity and template incompatibility

## Takeaways

C++ initialization is significantly more complicated than in other languages, with multiple syntax options producing different behaviors. The language gained greater flexibility but also greater complexity since C++11. Users should understand which initialization method calls which constructor and the implications for their code. C++20 aims to unify some of this complexity by making parentheses work for aggregates, reducing reliance on the problematic list initialization syntax.

Related talks