Вопрос знатокам С++: Время жизни ссылки на template объект

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

HKarel
Сообщения: 25
Зарегистрирован: 07 дек 2004, 14:50

Есть некий класс с функцией Func.

Код: Выделить всё

class TObj
{
public:
  ...
  String Func();
  ...
};
И есть следующий код:

Код: Выделить всё

  for ( int i = 0; i < List.Count; i++ )
  {
  	...
    const String &StrRef = List.Items( i )->Func();
    ...
  }
Возникает несколько вопросов:
1. Насколько правомерно присваивать ссылке StrRef значение функции?
2. На какю область памяти ссылается StrRef?
3. Может ли случиться так, что значение StrRef окажется не тем, которое вернула функция Func?

Сразу хочу оговориться, что в CBuilder6 значение ссылки соответствует значению функции, причем это справедливо как для константной так и для обычной ссылки.
Сложность - это мера непонимания.
Kolinus
Сообщения: 449
Зарегистрирован: 23 авг 2004, 14:02
Откуда: Минск

Насколько я помню в дереве разбора для приема значения функции создается переменная (с локальной областью видимости). Таким образом ссылку ты проинициализируешь данной переменной. То есть все в принципе корректно, единственное что ты не можешь проконтролировать момент вызова деструктора, то есть момент когда ссылка станет инвалидной. По идее это должно произойти при выходе из цикла.
В SAD - все в SAD.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Подобная программная конструкция неправомерна. После выполнения строки:

Код: Выделить всё

const String &StrRef = List.Items(i)->Func();
ссылка StrRef ссылается на неявно созданный объект, который автоматичски разрушается после выполнения присваивания. Т.о. любые последующий обращения к StrRef приведут к исключению.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
HKarel
Сообщения: 25
Зарегистрирован: 07 дек 2004, 14:50

Если бы было исключение "глупых" вопросов и не возникало бы, а так ссылка содержит именно то значение, которое возвращает ф-ция. Более того, если ссылка не константная ее значение можно еще и поменять. В свете последнего я больше склоняюсь к мнению Kolinus.
Сложность - это мера непонимания.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Значит Func возвращает по ссылке, другого быть не может. С++ - не фантик от конфеты, который бывает синий, а бывает красный.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Eugie
Сообщения: 708
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

Kolinus прав.
Подобная программная конструкция неправомерна. После выполнения строки:

Код: Выделить всё

const String &StrRef = List.Items(i)->Func(); 
ссылка StrRef ссылается на неявно созданный объект, который автоматичски разрушается после выполнения присваивания.
Romeo, возвращаемое значение, действительно, временный объект. Но его время жизни - до конца блока, т.е. как у локальной переменной.

2HKarel, по пунктам:
1. Правомерно, если не предполагается использовать ссылку за пределами блока, где 'живет' соотв. временный объект. Как в примере - без вопросов.
2. На область в стеке, соотв. временному объекту 'возвращаемое значение'.
3. Нет.

Важное замечание: при возврате по значению объекта пользовательского типа (класса), предполагающего для нормальной работы 'глубокое' копирование (напр., для Strring, если работаем с дин. памятью), необходимо ЯВНО определять конструктор копирования (КК по умолчанию просто почленно прсваивает поля, чего в этом случае недостаточно для корректной работы).
HKarel
Сообщения: 25
Зарегистрирован: 07 дек 2004, 14:50

Уважаемые господа, всем спасибо за ответы. Я узнал то, что хотел.
Еще один вариант ответа можно найти здесь
http://borland.xportal.ru/forum/viewtopic.php?t=12691
Действительно стандарт оговаривает данную ситуацию.
Сложность - это мера непонимания.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

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

Код: Выделить всё

_bstr_t GetSomeBSTRString();
...
void SomeFunction()
{
   ...
   char * strMyConvertedString = GetSomeBSTRString();
   cout << strMyConvertedString; // access violation exception
   ...
}
Класс _bstr_t имеет оператор char *, который возвращает указатель на строку, преварительно размещённую и инициализированную сконвертированным значением. В деструкторе, естественно, это внутренняя строка освобождается. Потому при попытке вывести сконвертированную строку имеем исключение.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Eugie
Сообщения: 708
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

Romeo, бывает :)
А вообще странно, что в твоем случае не работает: ведь, как мы выяснили, временный _bstr_t должен существовать до конца тела функции => и указатель на внут.буфер должен быть валидным в точке вызова
Eugie
Сообщения: 708
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

Все, разобрался: _bstr_t как раз реализует 'поверхностное' копирование, т.е. просто инкрементирут счетчик. Ессно, после вызова деструктора для локального объекта, его возвращаемая копия становится инвалидной.
Ответить