LINUX.ORG.RU

История изменений

Исправление 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.