Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions CppCoreGuidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -4671,6 +4671,7 @@ Concrete type rule summary:
* [C.10: Prefer concrete types over class hierarchies](#rc-concrete)
* [C.11: Make concrete types regular](#rc-regular)
* [C.12: Don't make data members `const` or references in a copyable or movable type](#rc-constref)
* [C.13: If one data member uses another, declare it before the other](#rc-lifetime)


### <a name="rc-concrete"></a>C.10: Prefer concrete types over class hierarchies
Expand Down Expand Up @@ -4792,6 +4793,102 @@ If you need a member to point to something, use a pointer (raw or smart, and `gs
Flag a data member that is `const`, `&`, or `&&` in a type that has any copy or move operation.


### <a name="rc-lifetime"></a>C.13: If one data member uses another, declare it before the other
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My reading of the title is (italic text is mine):

If one data member B uses another data member A, declare it (B) before the other (A)

This is in contrast to what the Discussion section says:

If data member B uses another data member A, then A must be declared before B so that A outlives B

I am not a native English speaker. Is my reading of the title wrong?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with your interpretation of the title and that they contradict.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe title could be 'If one data member uses another, declare it after the used member' ?

Copy link

@rainy-juzixiao rainy-juzixiao Mar 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think maybe it could rephrase to 'Declare a data member before members that depend on it' — it should convey roughly the same meaning?


##### Reason

Data members are initialized in the order they are declared, and destroyed in the reverse order.

##### Discussion

If data member `B` uses another data member `A`, then `A` must be declared before `B` so that `A` outlives `B`, meaning that `A`'s lifetime starts before and ends after `B`'s lifetime. Otherwise, during construction and destruction `B` will attempt to use `A` outside its lifetime.

##### Example; bad

// Bad: b uses a, but a is declared after b.
// Construction order is b then a; destruction order is a then b.
// So b touches a outside a's lifetime.
Copy link
Contributor

@bgloyer bgloyer Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like the build failed because a's isn't in the dictionary

Copy link

@rainy-juzixiao rainy-juzixiao Mar 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it could also rephrase this line to "So b touches a outside the lifetime of a.", which conveys the same meaning.

I think this phrasing might also express the intent more clearly, I'm not entirely sure


class X {
struct B {
string* p;
explicit B(string& a) : p(&a) {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
explicit B(string& a) : p(&a) {}
explicit B(string& a) : p{&a} {}

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es23-prefer-the--initializer-syntax

~B() { cout << *p; } // uses a (via p)
};

B b; // constructed first
string a = "some heap allocated string value"; // constructed after b; destroyed before b

public:
X() : b(a) {} // uses a before it is constructed -> use-before-alloc UB
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
X() : b(a) {} // uses a before it is constructed -> use-before-alloc UB
X() : b{a} {} // uses a before it is constructed -> use-before-alloc UB

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es23-prefer-the--initializer-syntax

~X() = default; // accesses a after it is destroyed -> use-after-free UB
};

##### Example; good

// Corrected: Just declare a before b

class X {
struct B {
string* p;
explicit B(string& a) : p(&a) {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
explicit B(string& a) : p(&a) {}
explicit B(string& a) : p{&a} {}

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es23-prefer-the--initializer-syntax

~B() { cout << *p; } // uses a (via p)
};

string a = "some heap allocated string value"; // constructed before b; destroyed after b
B b; // constructed second

public:
X() : b(a) {} // ok
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

~X() = default; // ok
};

##### Example; bad

This can also come up with concurrency. Ensure that an async operation that access a value is joined before the value it accesses is destroyed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This can also come up with concurrency. Ensure that an async operation that access a value is joined before the value it accesses is destroyed.
This can also come up with concurrency. Ensure that an async operation that accesses a value is joined before the value it accesses is destroyed.


class X {
public:
X()
: a(std::make_unique<int>(12))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
: a(std::make_unique<int>(12))
: a{std::make_unique<int>(12)}

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es23-prefer-the--initializer-syntax

{
b = std::make_unique<std::jthread>(
[this]{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Value: " << *a << std::endl;
});
}

std::unique_ptr<std::jthread> b;
std::unique_ptr<int> a;
};

##### Example; good

This can also come up with concurrency. Ensure that an async operation that access a value is joined before the value it accesses is destroyed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This can also come up with concurrency. Ensure that an async operation that access a value is joined before the value it accesses is destroyed.
This can also come up with concurrency. Ensure that an async operation that accesses a value is joined before the value it accesses is destroyed.


// Corrected: Just declare a before b

class X {
public:
X()
: a(std::make_unique<int>(12))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
: a(std::make_unique<int>(12))
: a{std::make_unique<int>(12)}

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es23-prefer-the--initializer-syntax

{
b = std::make_unique<std::jthread>(
[this]{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Value: " << *a << std::endl;
});
}

std::unique_ptr<int> a;
std::unique_ptr<std::jthread> b;
};

##### Enforcement

* Flag a member initializer that refers to an object before it is constructed.


## <a name="s-ctor"></a>C.ctor: Constructors, assignments, and destructors

Expand Down
Loading