VC2008中的自动指针构造函数
我有一个自动指针实现:
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)
这会导致临时自动 ptr 删除内存,并且 'a' 持有指向已释放内存的指针。
然而在 VC6 中它确实调用了正确的构造函数。 现在说了这么多,我也在 Linux 和 Mac 上使用 gcc,所以我编写的任何代码也需要在那里工作。 VC2008 禁止您在复制构造函数中使用非常量值变量。 另外,我也不想要“const”,因为复制构造函数获取内存块的所有权,这会删除正在复制的对象的所有权......从而修改它。
我如何才能在 VC 2005/2008 中实现此功能?
I have an auto pointer implementation:
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;
And that works fine in Visual C++ 6. However in Visual C++ 2005 or 2008 I can't return an auto pointer from a function without things going horribly wrong.
e.g.
GAutoString Func()
{
char *s = new char[4];
strcpy(s, "asd");
return s;
}
int main()
{
GAutoString a = Func();
/// a.Ptr is now garbage
}
What happens is that the compiler creates a temporary GAutoString to hold the return value for the function, and then in passing that to the variable 'a' on the stack calles the operator T*() of the temp variable, and then the GAutoPtr(T *ptr = 0) constructor, instead of just using the copy constructor: GAutoPtr(AutoPtrRef p)
This results in the temp auto ptr deleting the memory and 'a' holding a pointer to the freed memory.
However in VC6 it DOES call the right constructor. Now in saying all this I also use gcc on Linux and Mac, so whatever code I write needs to work there too. VC2008 prevents you from using a non-const by value variable in the copy constructor. Also I don't want "const" anyway, because the copy constructor takes ownership of the memory block which removes ownership from the object being copied... thus modifying it.
How can I make this work in VC 2005/2008?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这甚至可以在最近的 g++ 下编译吗? 我在我的 MacBook Pro 上尝试了它:
我可以编译它的唯一方法是让复制构造函数采用
const
引用,这正是我所怀疑的。 它看起来像 Herb Sutter 在他最近的 GotW 中发布了与此非常相似的内容。 如果没有充分的理由,我不会尝试复制 std::auto_ptr 的所有权转移语义。 您可能想查看 Boost.SmartPtr< 中的各种好东西/a>. 如果可能的话,请使用它们。如果您因某种原因无法 Boost,请阅读您最喜欢的
std::auto_ptr
实现,并特别注意std::auto_ptr_ref
类。 一旦你理解了它为什么存在以及它到底是如何做它所做的事情,那么就回去编写一个 auto-ptr 类。 此类的存在是为了解决您所看到的问题。 IIRC,Josuttis':标准 C++ 库对此进行了详细讨论。 我想那是我第一次真正理解它。Did this even compile under a recent g++? I tried it on my MacBook Pro and:
The only way that I can get this to compile is by making the copy constructor take a
const
reference which is what I had suspected. It looks like Herb Sutter posted about something very similar to this in his most recent GotW. I wouldn't try to replicate the ownership transfer semantic ofstd::auto_ptr
without a very good reason. You might want to look at the various goodies in Boost.SmartPtr. If possible, use them instead.If you can't Boost for whatever reason, then read your favorite
std::auto_ptr
implementation and pay particular attention to thestd::auto_ptr_ref
class. Once you understand why it is there and exactly how it does what it does, then go back and write an auto-ptr class. This class exists to get around the problem that you are seeing. IIRC, this is discussed in some detail in Josuttis': The Standard C++ Library. I think that is where I really understood it for the first time.您可以使用“explicit”关键字标记采用 T* 参数的构造函数。 我已经验证这有效并防止了虚假临时对象的创建,这是一种性能增强。 不过,任何使用该构造函数的人都不能再依赖编译器类型转换规则。 例如,您的函数将更改为:
这很烦人,但我认为在这种情况下这不一定是坏事,因为自动类型转换可能会令人困惑。
You could mark the constructor that takes the T* argument with the "explicit" keyword. I've verified that this works and prevents the creation of the spurious temporary object too, a performance enhancement. Anyone using that constructor could no longer rely on compiler type conversion rules, though. For example, you function would change to this:
It's annoying, but I don't think that is necessarily a bad thing in this case as automatic type conversions can be confusing.