Skip to content

C.48: Prefer default member initializers, also for non-constant initializers #2332

Closed

Description

@N-Dekker

The restriction "for constant initializers" on guideline C.48: Prefer default member initializers to member initializers in constructors for constant initializers appears unnecessary and undesirable.

For example, suppose a class has a creationTime member, that is initialized by now() in each of its constructors:

    class MyContainer {
        time_point<system_clock> creationTime;  // No default member initializer! Looks BAD to me.
        vector<int> data{};
    public:
        MyContainer() : creationTime{ system_clock::now() } {}
        explicit MyContainer(size_t n) : creationTime{ system_clock::now() }, data(n) {}
        MyContainer(initializer_list<int> values) : creationTime{ system_clock::now() }, data{ values } {}
    };

It appears preferable to use a default member initializer for MyContainer::creationTime, even though now() is not a constant. As follows:

    class MyContainer {
        time_point<system_clock> creationTime{ system_clock::now() };  // Preferable, right?
        vector<int> data{};
    public:
        MyContainer() = default;
        explicit MyContainer(size_t n) : data(n) {}
        MyContainer(initializer_list<int> values) : data{ values } {}
    };

In this example, using a default member initializer also avoids unnecessary code repetition, and it allows defaulting the default constructor.

In general, the guideline appears applicable to both constant and non-constant initializers.


Activity

  1. hsutter commented on Aug 26, 2026

    @hsutter
    Contributor

    Editors call: We generally like this but have one clarifying question. This change would still satisfy the two motivation goals of "avoids repetition" and "shortest code." We wonder whether it might sometimes violate the other two -- create maintenance problems and less efficient code, such as making it less obvious at use sites that local static variables are becoming dynamically initialization without obvious indication; constant initializers is not just for constants, they also enable or ensure static initialization.

  2. N-Dekker commented on Aug 26, 2026

    @N-Dekker
    ContributorAuthor

    @hsutter Thank you for your encouraging reply. Indeed, the PR for this issue (PR #2333) would certainly benefit "avoids repetition" and "shortest code." I don't think it would affect the efficiency, because the guideline is only applicable to those use-cases where replacing member-initializers (in constructor definitions) with default-member-initializers would produce semantically equivalent code. (The guideline is specifically for non-static data members.)

    The guideline will in some cases suggest to move some user code (the initialization) from a CPP file ("*.cpp") to the corresponding header file. That may affect the maintenance, but I don't think it would cause maintenance problems. Do you?

    This PR is meant as a generalization of PR #2330, which added numeric_limits<int>::min() as an example default-member-initializer. So now my motivation is: if we can use numeric_limits<int>::min() as default-member-initializer, we might as well use something like system_clock::now().

  3. hsutter commented on Oct 1, 2026

    @hsutter
    Contributor

    Editors call: Thanks!

    Regarding numeric_limits<T>::min, that is constexpr so it's not equivalent to now().

    We do want to avoid dynamic initialization in general wherever possible.

    We think the existing rule is right for the majority of code, and if you have a reason to initialize using something like system_clock::now() or thread::get_id() then we recommend putting it in the constructor which makes it more obvious that something dynamic is happening.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions