Посмотрите на следующий код. Цель здесь - вернуть ссылку через две функции (от ReferenceProvider::getReference()
до getRef()
до main()
):
#include <tchar.h>
#include <assert.h>
#include <string>
class BaseClass {
public:
virtual void write() const {
printf("In base class\n");
}
};
typedef BaseClass* BaseClassPointer;
class ChildClass : public BaseClass {
public:
virtual void write() const {
printf("In child class\n");
}
};
typedef ChildClass* ChildClassPointer;
//////////////////////////////////////////////////////////////////////////
ChildClass* g_somePointer = new ChildClass();
class ReferenceProvider {
public:
const BaseClassPointer& getReference() {
const BaseClassPointer& val = g_somePointer;
return val;
}
};
ReferenceProvider g_provider;
const BaseClassPointer& getRef() {
std::string test;
const BaseClassPointer& val = g_provider.getReference();
return val;
}
int _tmain(int argc, _TCHAR* argv[]) {
BaseClass* child = getRef();
assert(child == g_somePointer);
child->write();
return 0;
}
Теперь, при отладке этого кода (в Visual C ++), разрыв в return val;
в getRef()
даст вам такой экран:
Обратите внимание, что значения g_somePointer
и val
одинаковы. Теперь перешагните через оператор return, и вы увидите такой экран:
Обратите внимание, как val
стал недействительным (0xcccccccc
). Вероятно, это связано с тем, что стек getRef()
очищен, а val
больше не доступен.
Проблема в том, что child
в _tmain()
получит это недопустимое значение (0xcccccccc
), что сделает child
непригодным для использования. Итак, мой первый (и главный) вопрос: Как это сделать правильно?
(Обратите внимание, что это всего лишь пример из некоторого другого кода, над которым я работал. Его нужно структурировать так же, как и с использованием ссылок на указатели.)
Что делает все это очень странным (и трудным для отладки), так это то, что функция getRef()
работает при некоторых условиях:
- Если вы измените тип
g_somePointer
на BaseClass*
(с ChildClass*
)
- Если вы удалите локальную переменную в
getRef()
(то есть строка std::string test;
)
В обоих случаях ссылочная переменная val
(в getRef()
) не станет недействительной, и функция вернет правильный адрес указателя. Кто-нибудь может мне это объяснить?