Совокупная инициализация структуры с использованием собственных элементов данных
Это n-й вопрос об этом, но я не смог найти точный дубликат...
Предположим, что следующий код:
#include <iostream>
struct S {
int x;
int y;
};
class C {
public:
S s;
C() : s{123, s.x} {}
};
int main() {
std::cout << C().s.y << '\n';
}
Можно ли инициализировать s.y
следующим образом? (только JetBrains ReSharper жалуется на это со следующим: Object member this->s.x might not be initialized
).
Было бы здорово, если бы кто-то подтвердил свой ответ цитатой из стандарта.
Ответы
Ответ 1
Из С++ 14
8.5.1 Агрегаты [dcl.init.aggr]
1 Агрегат - это массив или класс (раздел 9) без каких-либо созданных пользователем конструкторов (12.1), без личных или
защищенные нестатические элементы данных (раздел 11), базовые классы (раздел 10) и виртуальные функции (10.3).
2 Когда агрегат инициализируется списком инициализаторов, как указано в 8.5.4, элементы списка инициализаторов
берутся как инициализаторы для членов совокупности, увеличивая индекс или порядок членов.
Это означает, что s.x сначала инициализируется 123, тогда s.y инициализируется с помощью s.x.
Без оптимизации GCC 6.3 генерирует
C::C():
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], rdi
mov rax, QWORD PTR [rbp-8] # read address of s
mov DWORD PTR [rax], 123 # write 123 to s.x (offset 0 from s)
mov rax, QWORD PTR [rbp-8] # read address of s again
mov edx, DWORD PTR [rax] # read contents of s.x to edx
mov rax, QWORD PTR [rbp-8] # read address of s
mov DWORD PTR [rax+4], edx # write s.y (offset 4 from s)
nop
pop rbp
ret
Что согласуется с тем, что говорят стандарты.
Ответ 2
Хотя казалось бы, что нет правила, которое явно заявляет, что этот трюк плохо сформирован, недостаточно для него иметь четко определенное поведение.
Я думаю, что у него есть некоторые проблемы с порядком оценки:
это правило определяет порядок оценки выражений в скобках; Конечно, есть и порядок инициализации члена.
Можно с уверенностью сказать, что каждый элемент структуры инициализируется после оценки соответствующего выражения в списке скобок (очевидно, s.x
в скобках списка оценивается до инициализации s.y
).
Однако, похоже, нет правила, которое указывало бы, что s.x
в вашем случае должно быть инициализировано перед оценкой второго элемента списка, например. программа могла бы оценить все выражения в списке скобок, прежде чем начать инициализацию полей структуры.
Конечно, отсутствие правила непросто доказать, но если оно не существует, оно выглядит как UB.
UPD: правило из ответа @PaulFloyd действительно очень похоже на то, чего не было в моем ответе, возможно это не UB в конце концов.