У меня есть автоматическая реализация указателя:
template <typename T, bool Arr = false>
class GAutoPtr
{
T *Ptr;
public:
typedef GAutoPtr<T, Arr> &AutoPtrRef;
GAutoPtr(T *ptr = 0)
{
Ptr = ptr;
}
GAutoPtr(AutoPtrRef p)
{
Ptr = p.Release();
}
~GAutoPtr() { Empty(); }
operator T*() { return Ptr; }
T *Get() { return Ptr; }
T *operator->() const { LgiAssert(Ptr); return Ptr; }
inline void Empty()
{
if (Arr)
delete [] Ptr;
else
delete Ptr;
Ptr = 0;
}
AutoPtrRef operator =(GAutoPtr<T> p)
{
Empty();
Ptr = p.Ptr;
p.Ptr = 0;
return *this;
}
void Reset(T *p)
{
if (p != Ptr)
{
Empty();
Ptr = p;
}
}
T *Release()
{
T *p = Ptr;
Ptr = 0;
return p;
}
};
typedef GAutoPtr<char, true> GAutoString;
typedef GAutoPtr<char16, true> GAutoWString;
И это прекрасно работает в Visual C ++ 6. Однако в Visual C ++ 2005 или 2008 я не могу вернуть автоматический указатель из функции, если все идет ужасно неправильно.
, например
GAutoString Func()
{
char *s = new char[4];
strcpy(s, "asd");
return s;
}
int main()
{
GAutoString a = Func();
/// a.Ptr is now garbage
}
Что происходит, так это то, что компилятор создает временную строку GAutoString для хранения возвращаемого значения функции, а затем при передаче этого значения в переменную 'a' в стеке вызывает оператор T * () переменной temp, а затем конструктор GAutoPtr (T * ptr = 0) вместо простого использования конструктора копирования: GAutoPtr (AutoPtrRef p)
Это приводит к тому, что temp auto ptr удаляет память, а 'a' держит указатель на освобожденную память.
Однако в VC6 он вызывает правильный конструктор. Говоря обо всем этом, я также использую gcc для Linux и Mac, поэтому любой код, который я пишу, должен работать и там. VC2008 запрещает использование неконстантной переменной по значению в конструкторе копирования. Кроме того, я не хочу, чтобы "const" в любом случае, потому что конструктор копирования становится владельцем блока памяти, который удаляет владение копируемого объекта ... изменяя его.
Как я могу сделать это в VC 2005/2008?