LINUX.ORG.RU

Ссылка по *nullptr?

 ,


0

2

У меня есть некая функция возвращающая ссылку. В некоторых случаях она должна вернуть заведомо невалидную ссылку и это должно легко проверятся тем кто ее вызывал, как то так

T& f(...){
   ...
   return *(T*)nullptr; 
   ...
};

Это немножко странно выглядит, но работает. Но на gcc8.3.0 уже не работает

T& ref = f(...);
if(&ref){...} //<== warning: nonnull argument ‘ref’ compared to NULL

насколько я понял он при оптимизации с -O3 эту проверку выкинул, а потом улетел с сегфолтом, дооптимизировался… gcc5.4.0 нормально работает.

В общем я готов поменять ссылку на указатель (хотя это слегка испоганит кое че дальше), но скажите - а с чего это вообще отвалилось то и насколько такая нулевая ссылка плоха? Ссылка же семантически ничем от указателя не отличается…

★★★

в общем ты всё правильно понял
для этого используй указатель
ссылки так нельзя использовать

return *(T*)nullptr;

это вообще дич
ты разыменовываешь нулевой указатель

Bad_ptr ★★★★ ()
Ответ на: комментарий от Bad_ptr

Нет, я по нему обращусь когда полезу в память на которую он указывает.

AntonI ★★★ ()

Ахах. В этом то вся и фишка ссылок, они не могут быть nullptr. Это специально было сделано. Для остального есть мастеркард сырые указатели. Но тут пришёл @AntonI и понеслась. Ор выше гор.

ox55ff ★★★★★ ()

Это сказано в стандарте?

$ cat main.cpp

template<typename T>
T& f()
{
    return *(T*)nullptr;
}

int main()
{
    int& a = f<int>();
}
$ clang++ -Wnull-dereference main.cpp
main.cpp:5:12: warning: binding dereferenced null pointer to reference has undefined behavior [-Wnull-dereference]
    return *(T*)nullptr;
           ^~~~~~~~~~~~
main.cpp:10:14: note: in instantiation of function template specialization 'f<int>' requested here
    int& a = f<int>();
             ^
1 warning generated.

Компилятор твой друг.

Ну и кастану @stasolog

fsb4000 ★★★★★ ()
Последнее исправление: fsb4000 (всего исправлений: 1)
Ответ на: комментарий от AntonI

Да, в [dcl.ref], даже про нулевой указатель разъяснили:

5 [...] A reference shall be initialized to refer to a valid object or function.
  [ Note: In particular, a null reference cannot exist in a well-defined program,
  because the only way to create such a reference would be to bind it to the
  “object” obtained by indirection through a null pointer, which causes undefined
  behavior.  As described in [class.bit], a reference cannot be bound directly to
  a bit-field.  — end note ]
xaizek ★★★★★ ()
Ответ на: комментарий от fsb4000

Ну и кастану @stasolog

А вот это было зря - он у меня все равно в игноре, но от Вас это звучит специфично. Можно вспомнить Ваши эпические перлы про отсутствие типизации в питоне (что позволено не-программисту вроде меня то не позволено Настоящему Профессионалу вроде Вас), но мне не хочется устраивать срач в своих темах, тем более сейчас на это нет времени.

Не делайте пожалуйста так больше, иначе мне придется заигнорить и Вас, что бы не отвлекаться от работы.

AntonI ★★★ ()
Последнее исправление: AntonI (всего исправлений: 1)
Ответ на: комментарий от AntonI

Ссылки нужны для того, чтобы обращаться к уже существующему объекту. В вашем случае лучше использовать указатели, т.к. они по обольшому счёту для этого и предназначены, а ссылки это лишь псевдоним, синтаксический сахар ценой кастрации полноценных указателей.

Еслим же хотите сделать с помощью ссылок, то тогда лучше переделать в bool f(T&object, …) и например в случае допустимых значений возвращать true, недопустимых false, но это всё же порочная практика и многие не рекомендуют передавть неconst ссылки

AKonia ★★ ()

Зачем все так сложно.

У меня так

INT  ParsingSting(
 ParsingStruct_  *pParsingStruct,
 INT             iModes,
 CHAR            *&pchString
);

Такой прием позволяет обеспечивает in/out работу с адресом.

Владимир

anonymous ()

то, что может вернуть невалидный обьект должно возвращать указатель. возврат указателя, это хинт для проверки, что он может быть нулевым. то что всегда возвращает валидный обьект - должно возвращать ссылку. это хинт - что нечего проверять, там все ок. если захотелось таки ввинтить невалидность ссылки можно обьявить экземпляр класса с именем NullRef, и возвращать ссылку на него. но это не особо хорошо, поскольку нарушает концепт понятия ссылки.

alysnix ★★ ()

Как там у @metaprog c «*&»?

Владимир

anonymous ()
Ответ на: комментарий от anonymous

На самом деле там есть некая функция библиотеки которая принимает функцию пользователя и передает в нее при вызове ссылку. Ссылка позволяет чуть меньше буков писать (. а не -> при задании всякой математики чуть лучше смотрится), но вот иногда надо как то сказать что объекта (аргумента) нет. Заводить под это лишний аргумент не хочется.

В общем меня тоже слегка конструкция

*(T*)nullptr

выморозила, но я торопился и решил оставить пока так. Поменяю на пойнтер,в крайнем случае всегда можно сделать

if(ptr){ T& ref = *ptr; ... }

;-)

AntonI ★★★ ()
Последнее исправление: AntonI (всего исправлений: 1)
Ответ на: комментарий от anonymous

Кто такой valid object — неизвестно

При этом нулевой указатель явно не указывает на valid object.

Notes не нормативны. Не являются правилами языка.

Я и сказал «разъяснили».

xaizek ★★★★★ ()

нулевая ссылка

Чисто теоретически.

«Нулевая ссылка» - это не невалидная ссылка. Даже «нулевой указатель» - это не невалидный указатель. Утверждение «0 - это плохое число для указателя» - это костыль.

Чисто теоретически. Для невалидного указателя в «множество указателей» надо добавить отдельный объект «невалидный указатель», который не равен любому указателю, даже 0.

Отображение большего множества в меньшее. Как следствие, это отображение не может быть однозначным, и надо хорошо знать последвия такой неоднозначности.

В твоем случае «чисто теоретически» правильно - это расширить множество указателей, например, использовать пару pair<valid, reference>, или std::optional. Или костылять, зная последствия.

anonymous ()
Ответ на: комментарий от anonymous

Чисто теоретически. … Даже «нулевой указатель» - это не невалидный указатель.

«Чисто теоретически» нулевой указатель это не невалидный указатель. [basic.compound]:

Every value of pointer type is one of the following:

  • a pointer to an object or function (the pointer is said to point to the object or function), or
  • a pointer past the end of an object ([expr.add]), or
  • the null pointer value for that type, or
  • an invalid pointer value.
anonymous ()
Ответ на: комментарий от anonymous

Да, но в сях например многие функции возвращают именно нулевой указатель если выделить ресурс не удалось?

Интересно, насколько этот костыль может приводить к проблемам в плюсах? nullptr же вот ввели, что со временем придется все проверки писать в виде

if(ptr!=nullptr)

? Это же аццкий ад будет…

AntonI ★★★ ()
Ответ на: комментарий от AntonI

На форуме троллят меня часто и всякую «муру» подписывают Владимир. И надо сказать весьма успешно.
Сумели создать нарицательный образ.
М-да …

Такова моя селяви.

Владимир

anonymous ()
Ответ на: комментарий от Siborgium

Да, я причем думал что со ссылками ровно та же фигня пока ты по ней не полез. Ссылка это же просто синтаксический сахар вокруг указателя… вот, оказывается я был не прав.

AntonI ★★★ ()
Ответ на: комментарий от anonymous

Показал (фото присылать не буду), а что это должно было дать?

anonymous ()
Ответ на: комментарий от anonymous

Все идёт к тому, чтобы мне начать генерировать уникальную подпись для каждого сообщения.

Но тогда злоумышленники не должны узнать алгоритм плавающей подписи, а добрые люди должны.

@Assembler, решите мой вопрос?

Вдадимир

anonymous ()
Ответ на: комментарий от AntonI

Да, но в сях например многие функции возвращают именно нулевой указатель если выделить ресурс не удалось?

*& упрощает не много код.
Поэтому то у меня адреса редко возвращаются.
Возвращаются в основном коды возврата.

PS: Впрочем все зависит от назначения API и иного контекста.

Владимир

anonymous ()
Ответ на: комментарий от AntonI

Ну вот мой «друг» Вдадимир «тут как тут».
Почалось …

Владимир

anonymous ()
Ответ на: комментарий от AntonI

Для начала, возвращать указатель – вполне нормальная практика, если ресурс может не быть получен. Тогда nullptr – признак неуспеха, и тогда нужно добавлять проверки. Ссылки гарантируют тебе валидность того, на что ссылаются. По крайней мере должны; стрелять в ногу так, как ты, непросто запретить. По топику читай концепт nullability.

Siborgium ★★★★ ()
Ответ на: комментарий от Siborgium

Для начала, возвращать указатель – вполне нормальная практика, если ресурс может не быть получен. Тогда nullptr – признак неуспеха, и тогда нужно добавлять проверки.

Иногда так, иногда этак.

Владимир

anonymous ()
Ответ на: комментарий от anonymous

STL - void, * и &.

Мало кто понимает потенциал Си, но многие «учат».

Владимир

anonymous ()
Ответ на: комментарий от AntonI

функции возвращают именно нулевой указатель

Как не очень релевантный пример: по какому адресу находтся таблица прерываний ДОС?

Это же аццкий ад будет…

anonymous ()

Ссылка же семантически ничем от указателя не отличается

Фундаментально отличается. Ссылка всегда на объект (который может быть в памяти или нет), указатель - на память (в которой объект может быть или нет). Расхожее мнение что ссылка это сахар для указателя ошибочно в общем случае.

anonymous ()
Ответ на: комментарий от AntonI

что со временем придется все проверки писать в виде if(ptr!=nullptr) ?

Не придется, в проверках ничего не поменялось.

anonymous ()
Ответ на: комментарий от Siborgium

Сам указатель является валидным, даже если содержит невалидное значение

«является валидым … невалидное»

Без противоречия это выглядело бы так: «указатель является указателем, даже если содержит любое значение, без разницы валидное или невалидное».

Или просто: «масло масленное» - «указатель является указателем»

anonymous ()
Ответ на: комментарий от anonymous

Ссылка всегда на объект (который может быть в памяти или нет)

Что значит что объект может не быть в памяти?

anonymous ()
Ответ на: комментарий от anonymous

past-the-end ссылок ты не признаёшь?

Где про них почитать?

Указатель тоже на объект

В том самом basic.compound читаю:

A valid value of an object pointer type represents either the address of a byte in memory (1.7) or a null pointer (4.10).

anonymous ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.