我有一个自动指针实现:
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*(),然后调用 GAutoPtr( T *ptr = 0) 构造函数,而不是仅仅使用复制构造函数:GAutoPtr(AutoPtrRef p)
这会导致 temp auto ptr 删除内存,并且 'a' 持有指向已释放内存的指针。
但是在 VC6 中,它确实调用了正确的构造函数。现在说这一切,我也在 Linux 和 Mac 上使用 gcc,所以我写的任何代码也需要在那里工作。VC2008 阻止您在复制构造函数中使用非常量值变量。另外我也不想要“const”,因为复制构造函数获取内存块的所有权,这会从被复制的对象中删除所有权......从而修改它。
如何在 VC 2005/2008 中完成这项工作?