Re[10]: const reference nullptr
От: prezident.mira Россия  
Дата: 16.07.17 11:50
Оценка:
NI>И что? CWG решила, что разыменование нулевого указателя должно быть разрешено, но официального (закреплённого в стандарте) описания поведения программы при таком разыменовании (кроме специального случая с typeid) по-прежнему нет.

Смотрим, что написано по ссылке http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html

This document contains the C++ core language issues for which the Committee (J16 + WG21) has decided that no action is required

Ещё раз смотрим в описание статуса NAD:

The working group has reached consensus that the issue is not a defect in the Standard. A Rationale statement describes the working group's reasoning.


О чём говорит issue №315, про который сказано, что это not a defect? Про то, что про обращение к не-статической функции-члену класса через нулевой указатель явно сказано, что оно undefined, а про обращение к статической не сказано undefined, но, автор issue считает что должно быть сказано

If f is static, however, there seems to be no such rule, and the call is only undefined if the dereference implicit in the -> operator is undefined. IMO it should be.

На что ему отвечают, что нет, не должно быть undefined, т.к.

*p is not an error when p is null unless the lvalue is converted to an rvalue



Так что не врите про "CWG решила, что разыменование нулевого указателя должно быть разрешено".
No action по внесению изменений, говорящих об UB в случае доступа через нулевой указатель к статической функции, is required, потому что отсутствие этого в стандарте not a defect, т.к. просто разыменование нулевого указателя, которое происходит при вычислении выражения вида E1.E2, где E2 обозначает статический член, а E1 это, собственно, разыменование нулевого указателя, разрешено. Именно "разрешено", а не "должно быть разрешено".
Отредактировано 16.07.2017 11:59 prezident.mira . Предыдущая версия .
Re[10]: const reference nullptr
От: prezident.mira Россия  
Дата: 16.07.17 12:22
Оценка:
Здравствуйте, N. I., Вы писали:

NI>В таких вопросах я бы ему не стал доверять Вот таким людям, как Майк Миллер, Йенс Маурер и Ричард Смит, я верю.


Ну вот Вам Ричард Смит https://groups.google.com/a/isocpp.org/d/msg/std-discussion/hG1Qx8a6Wjw/Q7aLfxfGAgAJ

The difference is that in core issue 315, the member function is a static member function.

This makes more sense if you think of non-static member functions as being passed an implied first parameter that is a reference to the class type. (The fact that 'this' is a pointer rather than a reference is a historical accident.) Just like any other reference parameter, it can't be bound to a dereferenced null pointer. But a static member function has no such parameter; the lvalue expression denoting the object is evaluated and then discarded, and null ("empty") lvalues are OK so long as you don't bind a reference to them or try to access an object through them.


Ещё вопросы есть, или в ответ опять будет "И что?" и тонна бла-бла вида "ну это смотря как это понимать"?
Re[11]: const reference nullptr
От: N. I.  
Дата: 16.07.17 13:19
Оценка:
prezident.mira:

NI>>Нет, это особый случай вычисления *(T *)nullptr из серии "игнорируйте, что мы писали вон там, и руководствуйтесь описанием поведения именно для данного случая".


PM>typeid не отменяет вычисления подвыражения вида *p и, если бы оно само по себе приводило к UB, то всё выражение с ним, как и остальное поведение программы стало бы undefined.


typeid(*p) — это специальная конструкция, в отношении которой действуют особые правила, и поведение выражения *p определяется контекстом его использования. Кстати, выражение *p, значение которого нигде не используется, — это тоже специальный случай. Например, здесь

#include <typeinfo>

struct Polymorphic
{
    virtual ~Polymorphic() {}
};

int main()
{
    Polymorphic volatile *p = nullptr;
    *p;         // undefined behavior
    typeid(*p); // well-defined
}

к обособленному *p применяется lvalue-to-rvalue conversion, потому что это volatile-qualified lvalue, и даже введение понятия empty lvalue от undefined behavior тут уже не спасёт. В случае с typeid(*p) такого lvalue-to-rvalue conversion не будет.
Re[11]: const reference nullptr
От: N. I.  
Дата: 16.07.17 13:22
Оценка:
prezident.mira:

NI>>И что? CWG решила, что разыменование нулевого указателя должно быть разрешено, но официального (закреплённого в стандарте) описания поведения программы при таком разыменовании (кроме специального случая с typeid) по-прежнему нет.


PM>CWG решила, что дефекта в стандарте нет, поэтому менять в нём ничего не нужно.


В каком конкретно месте его нет? Issue 232 уже закрыли?

PM>А что касается Вашего любимого правила "behavior for which this International Standard imposes no requirements" которое вы применяете как-то своеобразно, то результат применения унарного оператора * определён:

PM>

PM>the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points


Ещё раз: что будет результатом выражения *p, где p — нулевой указатель? "Не пойми что"? И что я дальше могу делать с этим "не пойми что"?

PM>Написано: "shall be a pointer to an object type,". Т.е. говорится про тип выражения.

PM>Я бы понял Ваши постоянные отсылки к определению UB, если бы было сказано "shall be a pointer to an object,".

Мои отсылки делались именно к отсутствию явного определения поведения в таком случае.

PM>Про значения указателя ничего не сказано — значит валидно для всех значений.


Нет, не для всех. Применение indirection к invalid pointer value — это явное undefined behavior:

[basic.stc.dynamic.deallocation]/4:

Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior. Any other use of an invalid pointer value has implementation-defined behavior.


Null pointer value не является invalid pointer value, поэтому в случае с разыменованием null pointer неопределённое поведение — это только следствие отсутствия явно определённого поведения.

PM>Требования к входному выражению предъявлены, результат описан.


Результат, которого там на самом деле не может быть? И что я могу делать с этим результатом? И какие правила при этом должен применять? Например, я захотел использовать *(int volatile *)nullptr в качестве discarded-value-expression. В какие пункты стандарта мне смотреть, чтоб выяснить, как оно себя может повести?
Re[12]: const reference nullptr
От: prezident.mira Россия  
Дата: 16.07.17 13:22
Оценка:
Здравствуйте, N. I., Вы писали:

NI>prezident.mira:


NI>>>Нет, это особый случай вычисления *(T *)nullptr из серии "игнорируйте, что мы писали вон там, и руководствуйтесь описанием поведения именно для данного случая".


PM>>typeid не отменяет вычисления подвыражения вида *p и, если бы оно само по себе приводило к UB, то всё выражение с ним, как и остальное поведение программы стало бы undefined.


NI>typeid(*p) — это специальная конструкция, в отношении которой действуют особые правила, и поведение выражения *p определяется контекстом его использования.


"Специальная конструкция" в случае неполиморфных классов. И тогда да, контекст, в котором находится *p, будет unevaluated и будут действовать особые правила.
В случае полиморфных классов обычный вычисляемый контекст.

NI>к обособленному *p применяется lvalue-to-rvalue conversion, потому что это volatile-qualified lvalue, и даже введение понятия empty lvalue от undefined behavior тут уже не спасёт.


Я оценил глубину Ваших познаний.
Re[11]: const reference nullptr
От: N. I.  
Дата: 16.07.17 13:24
Оценка:
prezident.mira:

PM>Да. Выделили malloc-ом "storage with the proper alignment and size for type T" и, если тип "have non-vacuous initialization", вызвали конструктор с использованием placement new.


Требует объект нетривиальную инициализацию или нет, для его создания необходимо использование конструкции, которая может создавать такие объекты. Само по себе выделение памяти никаких объектов не создаёт, и malloc создавать объекты не умеет.

PM>Я уже не в первый раз замечаю, что Вы не особо чистоплотны в методах ведения дискуссии. Либо просто не умеете читать.

PM>Написано "malloc alone is not sufficient to create an object" — "только malloc-а недостаточно для создания [всякого] объекта".

Не всякого, а вообще хоть какого-либо.

PM>Да, malloc-а недостаточно для создания всякого объекта, т.к. для некоторых типов кроме выделения стораджа может быть необходимо вызвать нетривиальный конструктор. См. http://eel.is/c++draft/basic.life#1 опять же.


Там сказано "is not sufficient", а не "may be insufficient".

PM>Больше похоже на то, что участники забыли про существование http://eel.is/c++draft/basic.life#1


Ничего они не забыли. Я тоже когда-то ошибочно предполагал, что выделить память с помощью функций std::malloc или ::operator new достаточно, чтоб получить этакое неограниченное множество объектов, не требующих нетривиальную инициализацию, и дальше с ними работать. А потом я получил разъяснение от Майка Миллера (председателя CWG), что это так не работает и объекты создаются только специальными конструкциями, вроде определения переменной и оператора new. Хочешь создать объект, скажем, типа int в памяти, выделенной malloc, — изволь использовать placement new. Даже если никакая инициализация объекта не нужна, необходимо выполнить что-то вроде new(storage) int, а иначе у тебя будет только дырка от бублика, а не объект.
Re[11]: const reference nullptr
От: N. I.  
Дата: 16.07.17 13:27
Оценка:
prezident.mira:

PM>Ну вот Вам Ричард Смит https://groups.google.com/a/isocpp.org/d/msg/std-discussion/hG1Qx8a6Wjw/Q7aLfxfGAgAJ

....
PM>Ещё вопросы есть, или в ответ опять будет "И что?" и тонна бла-бла вида "ну это смотря как это понимать"?

Это чё, текст стандарта или выражение воли комитета по стандартизации? В подтверждение статуса де-факто я тебе сам сколько хочешь цитат приведу; покажи лучше, где стандарт де-юре описывает требования к поведению.
Отредактировано 16.07.2017 13:34 N. I. . Предыдущая версия .
Re[12]: const reference nullptr
От: prezident.mira Россия  
Дата: 16.07.17 13:38
Оценка:
Здравствуйте, N. I., Вы писали:

NI>prezident.mira:


NI>>>И что? CWG решила, что разыменование нулевого указателя должно быть разрешено, но официального (закреплённого в стандарте) описания поведения программы при таком разыменовании (кроме специального случая с typeid) по-прежнему нет.


PM>>CWG решила, что дефекта в стандарте нет, поэтому менять в нём ничего не нужно.


NI>В каком конкретно месте его нет? Issue 232 уже закрыли?


232 — это исключительно про wording, а не про UB или не UB.

NI>Ещё раз: что будет результатом выражения *p, где p — нулевой указатель?


Что будет результатом — описано в пункте, который тут уже многократно цитировался и я не поленюсь сделать это ещё раз:

the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points


NI>"Не пойми что"?


"Не пойми что" там только из-за bad wording.

NI>И что я дальше могу делать с этим "не пойми что"?


Дальше Вы можете, например, применить оператор взятия адреса.

PM>>Написано: "shall be a pointer to an object type,". Т.е. говорится про тип выражения.

PM>>Я бы понял Ваши постоянные отсылки к определению UB, если бы было сказано "shall be a pointer to an object,".

NI>Мои отсылки делались именно к отсутствию явного определения поведения в таком случае.


Поведение определено во всех значениях, пока не сказано иное, как в процитированном Вами наже пункте про invalid pointer value.
И то, я подозреваю, что indirection throug означает использование его для доступа к значению, т.е. lvalue-to-rvalue conversion, а не просто применение оператора indirection.

PM>>Про значения указателя ничего не сказано — значит валидно для всех значений.


NI>Нет, не для всех. Применение indirection к invalid pointer value — это явное undefined behavior:


NI>[basic.stc.dynamic.deallocation]/4:

NI>

Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior. Any other use of an invalid pointer value has implementation-defined behavior.


Да. Поведение определено для всех значений, кроме тех, про которые явно не сказано, что оно не определено. Так же, как, например, со сложением int: не нужно перечислять все пары значений и их результат. Без этого понятно, что определено для всех. Кроме тех случаев, которые вызывают переполнение.

А пункт про "UB, если стандарт не определяет поведение" применяется примерно так:

Поведение описано для применения оператора * к выражению, которое имеет тип "указатель на объект (или функцию)". Что происходит при применении к выражению с другим типом? Это не определено, а, значит, по пункту про UB это UB.

А не так, как Вы его применяете:
NI>Null pointer value не является invalid pointer value, поэтому в случае с разыменованием null pointer неопределённое поведение — это только следствие отсутствия явно определённого поведения.


PM>>Требования к входному выражению предъявлены, результат описан.


NI>Результат, которого там на самом деле не может быть? И что я могу делать с этим результатом? И какие правила при этом должен применять? Например, я захотел использовать *(int volatile *)nullptr в качестве discarded-value-expression. В какие пункты стандарта мне смотреть, чтоб выяснить, как оно себя может повести?


На первый ряд вопросов я ответил выше, а про volatile Вы сами писали.
Re[12]: const reference nullptr
От: prezident.mira Россия  
Дата: 16.07.17 13:42
Оценка:
Здравствуйте, N. I., Вы писали:

NI>prezident.mira:


PM>>Ну вот Вам Ричард Смит https://groups.google.com/a/isocpp.org/d/msg/std-discussion/hG1Qx8a6Wjw/Q7aLfxfGAgAJ

NI>....
PM>>Ещё вопросы есть, или в ответ опять будет "И что?" и тонна бла-бла вида "ну это смотря как это понимать"?

NI>Это чё, текст стандарта или выражение воли комитета по стандартизации? В подтверждение статуса де-факто я тебе сам сколько хочешь цитат приведу; покажи лучше, где стандарт де-юре описывает требования к поведению.


Да, так я и предполагал. Сначала Вы требовали мнения авторитета из определённого круга лиц, а когда его предъявили — дали заднюю. В общем, слив засчитан.
Отредактировано 16.07.2017 13:44 prezident.mira . Предыдущая версия .
Re[13]: const reference nullptr
От: N. I.  
Дата: 16.07.17 16:32
Оценка:
prezident.mira:

PM>232 — это исключительно про wording, а не про UB или не UB.


Формулировки как раз и определяют поведение.

NI>>Ещё раз: что будет результатом выражения *p, где p — нулевой указатель?


PM>Что будет результатом — описано в пункте, который тут уже многократно цитировался и я не поленюсь сделать это ещё раз:

PM>

PM>the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points


Не будет там никакого lvalue referring to the object, просто в силу очевидной невозможности.

NI>>"Не пойми что"?


PM>"Не пойми что" там только из-за bad wording.


C составлением good wording, которое бы всех устраивало, дела пока как-то не очень, issue 232 висит уже заметно больше 10 лет. При этом стандартизаторам, наверное, уже 100500 раз задавали вопросы на этот счёт (и порядком ими задолбали), что, по идее, должно бы дать хороший стимул разрешить эту проблему. Однако признаков, что это наконец-то случится в ближайшем будущем, что-то пока не видать, а значит, не всё так просто.

NI>>И что я дальше могу делать с этим "не пойми что"?


PM>Дальше Вы можете, например, применить оператор взятия адреса.


И что я получу?

[expr.unary.op]/3:

Otherwise, if the type of the expression is T, the result has type “pointer to T” and is a prvalue that is the address of the designated object (1.7) or a pointer to the designated function.


Если lvalue не ссылается ни на объект, ни на функцию, то и адрес брать не у кого. Примерно такое же неявное undefined behavior, что и при разыменовании. Есть и другой похожий способ получения undefined behavior:

int &f()
{
    int local;
    return local;
}

int main()
{
    &f(); // undefined behavior
}

PM>И то, я подозреваю, что indirection throug означает использование его для доступа к значению, т.е. lvalue-to-rvalue conversion, а не просто применение оператора indirection.

Нет, это именно применение оператора разыменования, иначе там бы говорилось об accessing.

PM>Да. Поведение определено для всех значений, кроме тех, про которые явно не сказано, что оно не определено. Так же, как, например, со сложением int: не нужно перечислять все пары значений и их результат. Без этого понятно, что определено для всех. Кроме тех случаев, которые вызывают переполнение.


Хорошо, давай попробуем вычислить вот такое сложение: *(int *)nullptr + 1. Какое поведение тут будет?

PM>А пункт про "UB, если стандарт не определяет поведение" применяется примерно так:

PM>

PM>Поведение описано для применения оператора * к выражению, которое имеет тип "указатель на объект (или функцию)". Что происходит при применении к выражению с другим типом? Это не определено, а, значит, по пункту про UB это UB.

Согласно [intro.compliance], требование "the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type" относится к diagnosable semantic rules, и при его нарушении "a conforming implementation shall issue at least one diagnostic message" (это не undefined behavior).

PM>>>Требования к входному выражению предъявлены, результат описан.


По факту результат описан лишь для некоторых возможных случаев, но не для всех. Если описанный результат заведомо неверный, то ни о какой определённости речи быть не может.

NI>>Результат, которого там на самом деле не может быть? И что я могу делать с этим результатом? И какие правила при этом должен применять? Например, я захотел использовать *(int volatile *)nullptr в качестве discarded-value-expression. В какие пункты стандарта мне смотреть, чтоб выяснить, как оно себя может повести?


PM>На первый ряд вопросов я ответил выше, а про volatile Вы сами писали.


Вот только я не сказал, каким именно образом lvalue-to-rvalue conversion, будучи применённым к такому lvalue, порождает undefined behavior. И я бы с большим интересом посмотрел на выкладки, опирающиеся на явное указание того, что здесь имеет место undefined behavior (именно в соответствии с текстом стандарта, без правок, не имеющих официальный статус).
Отредактировано 16.07.2017 17:18 N. I. . Предыдущая версия .
Re[13]: const reference nullptr
От: N. I.  
Дата: 16.07.17 16:35
Оценка:
prezident.mira:

NI>>Это чё, текст стандарта или выражение воли комитета по стандартизации? В подтверждение статуса де-факто я тебе сам сколько хочешь цитат приведу; покажи лучше, где стандарт де-юре описывает требования к поведению.


PM>Да, так я и предполагал. Сначала Вы требовали мнения авторитета из определённого круга лиц


Я с самого начала провёл грань между состоянием дел де-факто (когда набор правил, фактически используемых разработчиками широкоизвестных компиляторов, представляет собой официальные правила стандарта, дополненные и модифицированные некими соглашениями, неофициально принятыми WG21) и официальными правилами стандарта как такового де-юре (без специальных комментаторов, говорящих, как правильно стандарт нужно читать, что нужно добавить, что нужно изменить и что выкинуть, чтоб получившийся набор правил совпадал с задумкой авторов стандарта).

PM>В общем, слив засчитан.


В игры кто кому засчитает слив можешь идти играть с детишками на каком-нибудь ЛОРе. Мне до подобных "засчитываний" никакого дела нет, и, думаю, многим другим пользователям тоже, потому что сюда люди обычно приходят для того, чтобы делиться знаниями и узнавать что-то новое от других, что выгодно отличает данный ресурс от всяких флеймерских помоек.
Re[6]: const reference nullptr
От: σ  
Дата: 25.08.18 16:12
Оценка:
NI>Если описания поведения нет, то де-юре получаем не что иное, как undefined behavior:

Разве? У оператора разыменования не сказано, что otherwise behavior is undefined. Следовательно, это diagnosable (semantic) rule.
http://eel.is/c++draft/intro.compliance#def:diagnosable_rules : The set of diagnosable rules consists of all syntactic and semantic rules in this document except for those rules containing an explicit notation that “no diagnostic is required” or which are described as resulting in “undefined behavior”.

Ещё такое написано
http://eel.is/c++draft/intro.compliance#2.2: If a program contains a violation of any diagnosable rule or an occurrence of a construct described in this document as “conditionally-supported” when the implementation does not support that construct, a conforming implementation shall issue at least one diagnostic message.

Получается, любая реализация, которая не выплёвывает diagnostic message при индеректе указателя, не указывающего на объект — не conforming?
Re[2]: const reference nullptr
От: B0FEE664  
Дата: 27.08.18 18:24
Оценка:
Здравствуйте, MasterZiv, Вы писали:

D>>
D>>const SomeClass& Class::getSomeClassVariable() const
D>>{
D>>    return *(SomeClass*)0;
D>>}
D>>

MZ>НАДО КИДАТЬ ИСКЛЮЧЕНИЕ!

Зачем исключение?
const SomeClass& Class::getSomeClassVariable() const
{
   assert(false && "It should never be called");
   static const SomeClass sSomeClass = SomeClass();
   return sSomeClass;
}
И каждый день — без права на ошибку...
Re: const reference nullptr
От: B0FEE664  
Дата: 04.09.18 08:19
Оценка:
Здравствуйте, Dair, Вы писали:

D>Есть ли смысл в подобном коде:

D>
D>const SomeClass& Class::getSomeClassVariable() const
D>{
D>    return *(SomeClass*)0;
D>}
D>

D>Или это яркий пример так называемого говнокода, как мне и показалось с первого взгляда?

Интересно, что в gcc std::array есть похожая конструкция:
 template<typename _Tp>
   struct __array_traits<_Tp, 0>
   {
     struct _Type { };

     static constexpr _Tp&   _S_ref(const _Type&, std::size_t) noexcept  { return *static_cast<_Tp*>(nullptr); }
   };


Используется в тех случаях, где по стандарту должно быть UB.
И каждый день — без права на ошибку...
Re[7]: const reference nullptr
От: N. I.  
Дата: 04.09.18 16:52
Оценка:
σ:

NI>>Если описания поведения нет, то де-юре получаем не что иное, как undefined behavior:


σ>Разве? У оператора разыменования не сказано, что otherwise behavior is undefined.


Там не только "otherwise", но и "if" поскипано.

σ>Получается, любая реализация, которая не выплёвывает diagnostic message при индеректе указателя, не указывающего на объект — не conforming?


А каким образом такое indirection что-то нарушает? Какие требования не выполняются?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.