VC2008中的自动指针构造函数

时间:2009-04-14 00:44:10

标签: visual-studio-2008 visual-c++ visual-studio-2005 copy-constructor auto-ptr

我有一个自动指针实现:

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中完成这项工作?

2 个答案:

答案 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对此进行了详细讨论。我认为这是我第一次真正理解的地方。