Страница 1 из 3
Вопрос знатокам С++: Время жизни ссылки на template объект
Добавлено: 07 дек 2004, 15:13
HKarel
Есть некий класс с функцией 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 значение ссылки соответствует значению функции, причем это справедливо как для константной так и для обычной ссылки.
Добавлено: 07 дек 2004, 15:18
Kolinus
Насколько я помню в дереве разбора для приема значения функции создается переменная (с локальной областью видимости). Таким образом ссылку ты проинициализируешь данной переменной. То есть все в принципе корректно, единственное что ты не можешь проконтролировать момент вызова деструктора, то есть момент когда ссылка станет инвалидной. По идее это должно произойти при выходе из цикла.
Добавлено: 07 дек 2004, 18:00
Romeo
Подобная программная конструкция неправомерна. После выполнения строки:
Код: Выделить всё
const String &StrRef = List.Items(i)->Func();
ссылка StrRef ссылается на неявно созданный объект, который автоматичски разрушается после выполнения присваивания. Т.о. любые последующий обращения к StrRef приведут к исключению.
Вопрос знатокам С++
Добавлено: 07 дек 2004, 21:54
HKarel
Если бы было исключение "глупых" вопросов и не возникало бы, а так ссылка содержит именно то значение, которое возвращает ф-ция. Более того, если ссылка не константная ее значение можно еще и поменять. В свете последнего я больше склоняюсь к мнению Kolinus.
Добавлено: 08 дек 2004, 09:26
Romeo
Значит Func возвращает по ссылке, другого быть не может. С++ - не фантик от конфеты, который бывает синий, а бывает красный.
Добавлено: 08 дек 2004, 13:44
Eugie
Kolinus прав.
Подобная программная конструкция неправомерна. После выполнения строки:
Код: Выделить всё
const String &StrRef = List.Items(i)->Func();
ссылка StrRef ссылается на неявно созданный объект, который автоматичски разрушается после выполнения присваивания.
Romeo, возвращаемое значение, действительно, временный объект. Но его время жизни - до конца блока, т.е. как у локальной переменной.
2
HKarel, по пунктам:
1. Правомерно, если не предполагается использовать ссылку за пределами блока, где 'живет' соотв. временный объект. Как в примере - без вопросов.
2. На область в стеке, соотв. временному объекту 'возвращаемое значение'.
3. Нет.
Важное замечание: при возврате по значению объекта пользовательского типа (класса), предполагающего для нормальной работы 'глубокое' копирование (напр., для Strring, если работаем с дин. памятью), необходимо ЯВНО определять конструктор копирования (КК по умолчанию просто почленно прсваивает поля, чего в этом случае недостаточно для корректной работы).
Добавлено: 08 дек 2004, 16:35
HKarel
Уважаемые господа, всем спасибо за ответы. Я узнал то, что хотел.
Еще один вариант ответа можно найти здесь
http://borland.xportal.ru/forum/viewtopic.php?t=12691
Действительно стандарт оговаривает данную ситуацию.
Добавлено: 09 дек 2004, 10:45
Romeo
Приношу свои извинения, был не прав. В случае ссылки, время жизни объекта действительно увеличивается до пределов текущего блока. Выводы сделал по одному из своих старых промахов. Привожу код, чтобы никто больше не наступил на эти грабли:
Код: Выделить всё
_bstr_t GetSomeBSTRString();
...
void SomeFunction()
{
...
char * strMyConvertedString = GetSomeBSTRString();
cout << strMyConvertedString; // access violation exception
...
}
Класс _bstr_t имеет оператор char *, который возвращает указатель на строку, преварительно размещённую и инициализированную сконвертированным значением. В деструкторе, естественно, это внутренняя строка освобождается. Потому при попытке вывести сконвертированную строку имеем исключение.
Добавлено: 09 дек 2004, 12:40
Eugie
Romeo, бывает

А вообще странно, что в твоем случае не работает: ведь, как мы выяснили, временный _bstr_t должен существовать до конца тела функции => и указатель на внут.буфер должен быть валидным в точке вызова
Добавлено: 09 дек 2004, 13:00
Eugie
Все, разобрался: _bstr_t как раз реализует 'поверхностное' копирование, т.е. просто инкрементирут счетчик. Ессно, после вызова деструктора для локального объекта, его возвращаемая копия становится инвалидной.