我有一个自动指针实现:
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中,我无法从函数返回自动指针而不会出现可怕的错误。
e.g。
GAutoString Func()
{
char *s = new char[4];
strcpy(s, "asd");
return s;
}
int main()
{
GAutoString a = Func();
/// a.Ptr is now garbage
}
编译器会创建一个临时GAutoString来保存函数的返回值,然后将其传递给堆栈中的变量“a”,调用temp变量的运算符T *(),然后GAutoPtr(T * ptr = 0)构造函数,而不是仅仅使用复制构造函数:GAutoPtr(AutoPtrRef p)
这导致temp auto ptr删除内存,'a'持有指向释放内存的指针。
但是在VC6中,它会调用正确的构造函数。现在说这一切我也在Linux和Mac上使用gcc,所以我编写的代码也需要在那里工作。 VC2008阻止您在复制构造函数中使用非const by值变量。此外,我还不想要“const”,因为复制构造函数取得了内存块的所有权,从而从正在复制的对象中删除所有权......从而修改它。
如何在VC 2005/2008中完成这项工作?
答案 0 :(得分:1)
您可以使用“explicit”关键字标记带有T *参数的构造函数。我已经验证了这种方法可以防止虚假临时对象的创建,性能提升。但是,任何使用该构造函数的人都不能再依赖编译器类型转换规则了。例如,您的功能将更改为:
GAutoString Func()
{
char *s = new char[4];
strcpy(s, "asd");
return GAutoString(s);
}
这很烦人,但我认为在这种情况下这不一定是坏事,因为自动类型转换可能会令人困惑。
答案 1 :(得分:1)
这是否在最近的g ++下编译?我在我的MacBook Pro上尝试过:
xxx.cpp: In function ‘AutoString func()’:
xxx.cpp:52: error: no matching function for call to ‘AutoPtr<char, true>::AutoPtr(AutoString)’
xxx.cpp:12: note: candidates are: AutoPtr<T, isArray>::AutoPtr(AutoPtr<T, isArray>&) [with T = char, bool isArray = true]
xxx.cpp:9: note: AutoPtr<T, isArray>::AutoPtr(T*) [with T = char, bool isArray = true]
xxx.cpp:52: error: initializing temporary from result of ‘AutoPtr<T, isArray>::AutoPtr(T*) [with T = char, bool isArray = true]’
我可以通过使复制构造函数采用我所怀疑的const
引用来实现编译的唯一方法。在他最近的GotW中看起来像Herb Sutter posted about something very similar。我没有尝试在没有充分理由的情况下复制std::auto_ptr
的所有权转移语义。你可能想看看Boost.SmartPtr中的各种好东西。如果可能,请改用它们。
如果因任何原因无法提升,请阅读您最喜欢的std::auto_ptr
实施,并特别注意std::auto_ptr_ref
课程。一旦你理解了它为什么存在以及它究竟是如何做的,那就回去写一个auto-ptr类。这个类的存在是为了解决您所看到的问题。 IIRC,Josuttis': The Standard C++ Library对此进行了详细讨论。我认为这是我第一次真正理解的地方。