VC2008中的自动指针构造函数

发布于 2024-07-17 04:56:44 字数 1730 浏览 12 评论 0原文

我有一个自动指针实现:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

枯叶蝶 2024-07-24 04:56:44

这甚至可以在最近的 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 引用,这正是我所怀疑的。 它看起来像 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:

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]’

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 of std::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 the std::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.

七秒鱼° 2024-07-24 04:56:44

您可以使用“explicit”关键字标记采用 T* 参数的构造函数。 我已经验证这有效并防止了虚假临时对象的创建,这是一种性能增强。 不过,任何使用该构造函数的人都不能再依赖编译器类型转换规则。 例如,您的函数将更改为:

GAutoString Func()
{
    char *s = new char[4];
    strcpy(s, "asd");
    return GAutoString(s);
}

这很烦人,但我认为在这种情况下这不一定是坏事,因为自动类型转换可能会令人困惑。

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:

GAutoString Func()
{
    char *s = new char[4];
    strcpy(s, "asd");
    return GAutoString(s);
}

It's annoying, but I don't think that is necessarily a bad thing in this case as automatic type conversions can be confusing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文