析构函数抛出异常时多次调用删除

问题描述 投票:0回答:1

如果使用 Visual Studio 编译,上面的代码可以工作。如果析构函数抛出异常,则不会调用

operator delete
。如果析构函数没有抛出异常,则调用
operator delete
。但如果在 Linux 上使用 gcc 编译,相同的代码会导致分段错误。即使班级中没有
std::string
成员,它也不起作用。它以“free():在 tcache 2 中检测到双重释放”结束。这意味着即使析构函数抛出异常,也会调用
operator delete
。根据 C++ 标准,该行为是否未定义?如果是这样,是否意味着如果第一次调用抛出异常就无法再次调用
delete

#include <string>
#include <iostream>

class MyClass
{
public:
    void *operator new(size_t size)
    {
        void *p = std::malloc(size);
        if (!p) throw std::bad_alloc();
        return p;
    }

    void operator delete(void *p)
    {
        std::free(p);
    }

    ~MyClass() noexcept (false)
    {
        if (s == "123") throw int{};
    }

    std::string s{"123"};
};

int main()
{
    MyClass* myobject = new MyClass{};

    try
    {
        delete myobject;
    }
    catch (...) {}

    std::cout << "<" << myobject->s << ">";
    myobject->s = "abc";

    delete myobject;

    return 0;
}

我在 Windows 上使用 Visual Studio 和 Linux 上使用 GCC 编译并运行了代码。我希望它可以在两个平台上运行,但它不能在带有 GCC 的 Linux 上运行

c++ exception destructor delete-operator
1个回答
0
投票

GCC 是正确的,MSVC 是错误的(像往常一样,我敢说)。

[expr.delete]
中有这样的:

[注3: 无论对象或数组的某些元素的析构函数是否抛出异常,都会调用释放函数。 — 尾注]

注释并不规范,但如果您愿意,您可以阅读上面的规范性措辞。

© www.soinside.com 2019 - 2024. All rights reserved.