LINUX.ORG.RU

[C++] ворзврат ссылки на локальный объект

 


0

4

Коллеги, объясните, как оно работает (если можно, со ссылками на документацию)

Почему функция

 
MyClass& func(const MyClass &rhs)
{
  Myclass tmp = rhs; // Конструктор копии определен корректно
  // преобразование tmp для заданных целей

  return tmp;
}
работает неверно (сегфолтится),

а функция

 
MyClass func(const MyClass &rhs)
{
  Myclass tmp = rhs; // Конструктор копии определен корректно
  // преобразование tmp для заданных целей

  return tmp;
}
работает корректно?

Правильно ли я понимаю, что return tmp вызывает конструктор копии, прежде, чем разрушить tmp по выходу из функции? Или это как-то по-другому работает? Или обе версии неправильные?

★★★★★

Ответ на: комментарий от Miguel

> Собственно, не проблема. Вполне логичный код:

Господи. Так и this может окозаться 0. И еще много что. И указывать можно в произвольную область памяти.

Если ты отстреливаешь себе ногу - не будем же мы забирать у тебя пистолет

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

>Он не сможет быть null в runtime.

А слово static в StaticRejectNull типа совсем ничего не означает. Этот так, префикс такой.

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

Ссылка должна быть инициализирована при создании и валидна на протяжении всей свой жизни.

Вообще-то, это немножко отличается от «не NULL».

И всё равно никак не гарантируется.

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

Так и this может окозаться 0.

Конечно.

Если ты отстреливаешь себе ногу - не будем же мы забирать у тебя пистолет

Какая из этих трёх функций подходит под «отстрелить себе ногу?»

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

Когда мы говорим - ссылка, мы подразумеваем, что не должны передать нулл

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

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

>> Ссылка должна быть инициализирована при создании и валидна на протяжении всей свой жизни.

Вообще-то, это немножко отличается от «не NULL».


Чем? Уточню, «не NULL» == «валидна». Т.е. указывает на существующий объект.

И всё равно никак не гарантируется.


Разумеется. Всегда есть оператор "(T)", он же «T()».

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

А вообще. Вы сами себе выстрелили. С какого перепоя вы стали разыменовывать непроверенный указатель?

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

«не NULL» == «валидна».

Это что-то новенькое.

Начнём с того, что на некоторых архитектурах NULL может указывать на валидный объект. PlayStation 3 SPU, например.

С другой стороны, объект вполне может быть не NULL, но, тем не менее, не валидным. Собственно, если сделать ему delete, то указатель-то останется.

Всегда есть оператор "(T)"

Да даже и без явных кастов.

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

С какого перепоя вы стали разыменовывать непроверенный указатель?

Ну, собственно, это то, о чём я и говорю – постоянные проверки в рантайме, иначе получается бред.

С другой стороны, подобный код может и рабочим оказаться. Как и код, где this=NULL. Приходилось встречать и такое.

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

> Это что-то новенькое.

Ничего «новенького». Выражение «не NULL» я использовал как полный синоним выражения «ссылка на валидный объект». Оно несколько короче.

Начнём с того, что на некоторых архитектурах NULL может указывать на валидный объект. PlayStation 3 SPU, например.


А закончим тем, что это утверждение бессмыслено. Стандарт С явно требует, чтобы значение NULL представляло собой адрес, обращение по которому не допустимо. Если компилятор это позволяет, то он не совместим со стандартом, только и всего.

И да, если ты до сих пор не знаешь, что «NULL != 0», то, согласись, это не проблемы языка С/С++. ;)

С другой стороны, объект вполне может быть не NULL, но, тем не менее, не валидным.


Объект не может быть NULL или не NULL просто по тому, что NULL - это адрес, а не объект.

Собственно, если сделать ему delete, то указатель-то останется.


И что? При чём тут указатель?

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

> Если компилятор это позволяет,

позволяет обращаться по этому адресу

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

когда получил ссылку, ты не проверяешь. а когда получил указатель - проверяешь.

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

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

Miguel ★★★★★
()

первый вариант возвращает MyClass& - это обман :)

Почти аналог, только без синтаксического сахара такой:

MyClass* func(const MyClass &rhs)
{
  Myclass tmp = rhs; // Конструктор копии определен корректно
  // преобразование tmp для заданных целей

  return &tmp;
}
только при вызове вместо

MyClass x = func(xxx)

в моём примере надо использовать

MyClass x = *(func(xxx))
Что по факту и происходит. Поэтому происходит сегфолт при разыменовании указателя на элемент стека, который уже вытолкнут (при завершении func)

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

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

В данном случае вопрос, где ставить барьер

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