SeniorДебаггингИногдаЕщё не отвечали
Почему порядок инициализации членов может вызывать неочевидные ошибки?
Этот Buffer должен задавать размер вектора из n, но построенный вектор получает непредсказуемый размер и может повредить память.
#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);
}
Найдите и исправьте ошибку.
Нестатические поля данных инициализируются в порядке объявления, никогда в порядке их появления в списке инициализации. Если инициализатор одного поля читает другое поле, объявленное позже, то это поле ещё неинициализированный мусор. Включите -Wreorder, чтобы поймать это.
- ✗Считать, что инициализацией управляет порядок списка инициализации, а не порядок объявления
- ✗Инициализировать одно поле из другого, объявленного позже, читая неинициализированный мусор
- ✗Игнорировать или отключать предупреждение
-Wreorderвместо исправления реального порядка
- →Действует ли то же правило порядка для под-объектов базовых классов относительно членов?
- →Как перестроить класс, чтобы убрать зависимость инициализации между членами?
Оглавление
Проблема
#include <cstddef>
#include <vector>
struct Buffer {
std::vector<int> data_;
std::size_t size_; // объявлено ПОСЛЕ data_
// намерение: size_ инициализируется первым, затем data_ использует его
explicit Buffer(std::size_t n)
: size_(n) // (1) в списке первым...
, data_(size_) // (2) ...но data_ объявлено раньше — UB!
{}
};
int main() {
Buffer b(10); // data_ строится из ещё-мусорного size_
}
Поля инициализируются в порядке объявления: сначала data_, затем size_. Поэтому в точке (2) data_ строится из size_, которое ещё не инициализировано — значение мусорное, размер вектора непредсказуем. Список инициализатора пишет их в обратном порядке, что и сбивает с толку. Флаг -Wreorder ловит ровно этот случай.
Решение — declaration order = dependency order
struct Buffer {
std::size_t size_; // объявлено ПЕРВЫМ — нет зависящих от него полей выше
std::vector<int> data_;
explicit Buffer(std::size_t n)
: size_(n) // инициализируется первым по порядку объявления
, data_(size_) // size_ уже валиден
{}
};Оглавление