История изменений
Исправление byko3y, (текущая версия) :
Стандарт C это позволяет делать, потому что корректная программа не должна содержать UB. Тут либо в печь такой стандарт (да и язык заодно), либо не надо говнокод писать. Другими словами, либо трусы наденьте, либо крестик снимите
Оба стандарта C и C++ на самом деле замалчивают эту проблему и никак не определяют это поведние. То есть, это не UB и не корректное поведение — как хочешь, так и реализуй. А проблема возникает из-за того, что стандарт C++ §5.2.5/3 говорит
If E1 has the type “pointer to class X,” then the expression E1->E2 is converted to the equivalent form (*(E1)).E2;
Но проблема в том, что оба стандарта отказываются говорить, что является настоящим доступом. (*(E1)).E2 — это lvalue, у которого, например, можно взять адрес, что де-факто большинство компиляторов интерпретирует как «доступа к значению по этому адресу не происходило». Например, я могу сделать
struct int_t {
int a
};
int *pntr = &((int_t *)NULL)->a;
И ни один компилятор Си мне не выдаст ошибку при компиляции или выполнении. Вот если я разыменую полученный указатель дальше, например, через «return *pntr» — это ошибка, это UB. Стандарт C++ не определил, в какой момент происходит реальный доступ по некорректному адресу для статичных членов класса, из-за чего начался традиционный разброд и шатание, примерно как в случае strict aliasing.
Для нестатичных членов, к слову, этот момент вполне себе определен (§9.3.1/1):
If a nonstatic member function of a class X is called for an object that is not of type X, or of a type derived from X, the behavior is undefined.
Исправление byko3y, :
Стандарт C это позволяет делать, потому что корректная программа не должна содержать UB. Тут либо в печь такой стандарт (да и язык заодно), либо не надо говнокод писать. Другими словами, либо трусы наденьте, либо крестик снимите
Оба стандарта C и C++ на самом деле замалчивают эту проблему и никак не определяют это поведние. То есть, это не UB и не корректное поведение — как хочешь, так и реализуй. А проблема возникает из-за того, что стандарт C++ §5.2.5/3 говорит
«If E1 has the type “pointer to class X,” then the expression E1->E2 is converted to the equivalent form (*(E1)).E2;»
Но проблема в том, что оба стандарта отказываются говорить, что является настоящим доступом. (*(E1)).E2 — это lvalue, у которого, например, можно взять адрес, что де-факто большинство компиляторов интерпретирует как «доступа к значению по этому адресу не происходило». Например, я могу сделать
struct int_t {
int a
};
int *pntr = &((int_t *)NULL)->a;
И ни один компилятор Си мне не выдаст ошибку при компиляции или выполнении. Вот если я разыменую полученный указатель дальше, например, через «return *pntr» — это ошибка, это UB. Стандарт C++ не определил, в какой момент происходит реальный доступ по некорректному адресу, из-за чего начался традиционный разброд и шатание, примерно как в случае strict aliasing.
Исходная версия byko3y, :
Стандарт C это позволяет делать, потому что корректная программа не должна содержать UB. Тут либо в печь такой стандарт (да и язык заодно), либо не надо говнокод писать. Другими словами, либо трусы наденьте, либо крестик снимите
Оба стандарта C и C++ на самом деле замалчивают эту проблему и никак не определяют это поведние. То есть, это не UB и не корректное поведение — как хочешь, так и реализуй. А проблема возникает из-за того, что стандарт C++ §5.2.5/3 говорит
«If E1 has the type “pointer to class X,” then the expression E1->E2 is converted to the equivalent form (*(E1)).E2;»
Но проблема в том, что оба стандарта отказываются говорить, что является доступом (*(E1)).E2 — это lvalue, у которого, например, можно взять адрес, что де-факто большинство компиляторов интерпретирует как «доступа к значению по этому адресу не происходило». Например, я могу сделать
struct int_t {
int a
};
int *pntr = &((int_t *)NULL)->a;
И ни один компилятор Си мне не выдаст ошибку при компиляции или выполнении. Вот если я разыменую полученный указатель дальше, например, через «return *pntr» — это ошибка, это UB. Стандарт C++ не определил, в какой момент происходит реальный доступ по некорректному адресу, из-за чего начался традиционный разброд и шатание, примерно как в случае strict aliasing.