为什么不〜后跟:: parse

mar*_*ark 14 c++ c++11

在Andrei Alexandrescu关于错误处理的讨论中:

参见C++和2012年之后:Andrei Alexandrescu - C++中的系统错误处理(大约30分钟)

Andrei提供以下代码:

~Expected()
{
    using std::exception_ptr;
    if (gotHam) ham.~T();
    else spam.~exception_ptr();
}
Run Code Online (Sandbox Code Playgroud)

这个析构函数正在清理一个union包含某种类型T或一个类型的析构函数std::exception_ptr.工会填充使用placement new.

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

    else spam.~std::exception_ptr();
Run Code Online (Sandbox Code Playgroud)

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

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

以下代码是否是有效的替代方案?

    else delete spam;
Run Code Online (Sandbox Code Playgroud)

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

n. *_* m. 10

安德烈可能会使用,using std::exception_ptr;因为他的编译器坏了.

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

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

它确实与gcc编译.

如果由于某种原因需要使用qualified-name,spam.std::exception_ptr::~exception_ptr();也要编译.


Gor*_*pik 8

这里的问题是,这~std::exception_ptr()不是你试图调用的函数的名称,而只是~exception_ptr().并且,由于它属于不同命名空间中的类,因此无法访问(编辑:虽然它应该可以根据C++ 11标准中的§3.4.5/ 3访问,正如nm在他的回答中指出的那样,但是微软编译器以这种方式运行).

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

else spam.std::exception_ptr::~exception_ptr(); // This is legal
Run Code Online (Sandbox Code Playgroud)

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

  • 记住这会抑制虚函数调用机制.因此,如果`spam`将是一个引用或指针(`spam->`),这将停止工作. (2认同)