Why can member initialization order cause subtle bugs?
This Buffer is meant to size its vector from n, but the constructed vector has an unpredictable size and may corrupt memory.
#include <cstddef>
#include <vector>
struct Buffer {
std::vector<int> data_;
std::size_t size_;
explicit Buffer(std::size_t n)
: size_(n)
, data_(size_)
{}
};
int main() {
Buffer b(10);
}
Find and fix the bug.
Non-static data members are initialized in declaration order, never in the order they appear in the member initializer list. If one member's initializer reads another member declared later, that member is still uninitialized garbage. Enable -Wreorder to catch this.
- ✗Assuming initializer-list order drives initialization rather than declaration order
- ✗Initializing one member from another declared later, reading uninitialized garbage
- ✗Ignoring or disabling the
-Wreorderwarning instead of fixing the real ordering
- →Does the same ordering rule apply to base-class subobjects relative to members?
- →How can you restructure a class to remove an inter-member initialization dependency?
The problem
#include <cstddef>
#include <vector>
struct Buffer {
std::vector<int> data_;
std::size_t size_; // declared AFTER data_
// intent: size_ initialized first, then data_ uses it
explicit Buffer(std::size_t n)
: size_(n) // (1) first in the list...
, data_(size_) // (2) ...but data_ is declared earlier — UB!
{}
};
int main() {
Buffer b(10); // data_ built from still-garbage size_
}
Members are initialized in declaration order: data_ first, then size_. So at point (2) data_ is constructed from size_, which is not yet initialized — the value is garbage and the vector's size is unpredictable. The initializer list writes them in the reverse order, which is what misleads the reader. The -Wreorder flag catches exactly this case.
The fix — declaration order = dependency order
struct Buffer {
std::size_t size_; // declared FIRST — nothing above depends on it
std::vector<int> data_;
explicit Buffer(std::size_t n)
: size_(n) // initialized first by declaration order
, data_(size_) // size_ is already valid
{}
};