14

在 Andrei Alexandrescu 关于错误处理的演讲中:

请参阅C++ 和超越 2012:Andrei Alexandrescu - C++ 中的系统错误处理(大约 30 分钟)

Andrei 提供了以下代码:

~Expected()
{
    using std::exception_ptr;
    if (gotHam) ham.~T();
    else spam.~exception_ptr();
}

这个析构函数正在清理union包含某种类型T或 a 的 a std::exception_ptr。联合使用 填充placement new

Andrei 然后解释说这using std::exception_ptr;是必要的,因为以下代码不会解析:

    else spam.~std::exception_ptr();

这意味着如果您需要显式调用不同命名空间中类的析构函数,则始终需要使用 using 指令。

为什么第二个示例不解析?

以下代码会是一个有效的替代方案吗?

    else delete spam;

这是否与显式调用析构函数具有相同的影响std::exception_ptr

4

3 回答 3

10

Andrei 可能会使用using std::exception_ptr;,因为他的编译器坏了。

没有必要。spam.~exception_ptr();没有它应该编译得很好。

3.4.5/3。如果 unqualified-id 是 ~type-name,则在整个后缀表达式的上下文中查找类型名称。如果对象表达式的类型 T 是类类型 C,则类型名称也在类 C 的范围内查找。

它确实可以用 gcc 编译。

如果出于某种原因需要使用限定名,spam.std::exception_ptr::~exception_ptr();也可以编译。

于 2013-01-04T12:50:45.730 回答
8

这里的问题是,这~std::exception_ptr()实际上并不是您要调用的函数的名称,而只是~exception_ptr(). 而且,由于它属于不同命名空间中的一个类,所以它是不可访问的(编辑:虽然它应该可以根据 C++11 标准中的 §3.4.5/3 访问,正如 nm 在他的回答中指出的那样,但 Microsoft编译器以这种方式运行)。

您可以选择将类引入命名空间:使用限定的类名进行显式调用:

else spam.std::exception_ptr::~exception_ptr(); // This is legal

至于你的第二个问题,正如 R. Martinho Fernandes 在评论中正确解释的那样,调用delete运算符并不等同于仅调用析构函数:它还调用了命名笨拙的 function operator delete()

于 2013-01-04T12:27:03.833 回答
3

语法spam.~std::exception_ptr是不允许的,因为语法要求一个 id 表达式,~std::exception_ptr而不是一个,正如 Gorpik 指出的那样,你需要spam.std::exception_ptr::~exception_ptr(). 但我不明白为什么需要限定的原因,在描述语法的子句中,提醒说

因为一个类的名字被插入到它的类范围内(第 9 条),一个类的名字也被认为是这个类的一个嵌套成员。

所以我认为spam.~exception_ptr()即使没有 using 子句也应该是有效的。顺便提一句

namespace ns {
struct Foo {};
}

void f()
{
    ns::Foo x;
    x.~Foo();
}

使用我可以访问的所有 g++ 干净地编译(包括非常旧的 2.95)。这似乎证实了我的观点,如果它在 C++11 的更新联合类型的上下文中不起作用,那么它是实现中的一个错误。

使用 g++ 4.7.1 进行编辑,以下内容也使用 -std=c++11 进行编译。

namespace ns {
struct Foo {};
}

struct Bar {};

union U {
    ns::Foo f;
    Bar b;
};

struct C {
    bool b;
    U u;
    ~C() {
        if (b)
            u.f.~Foo();
        else
            u.b.~Bar();
    }                
};

void f()
{
    C c;
}

因此,Andrei 一直在试图解决一个不需要解决的问题(要么是他使用的编译器中的错误,要么是忘记了类名是在类的范围内导入的事实)。

于 2013-01-04T12:36:47.210 回答