箭头运算符 -> 和范围解析运算符 :: 的组合有何含义?

Soc*_*cob 2 c++ syntax member-access scope-resolution-operator

cppreference.com \xe2\x80\x93 \xe2\x80\x9cQualified name Lookup\xe2\x80\x9d上,我发现了这个奇怪的代码示例:

\n
struct C { typedef int I; };\n\ntypedef int I1, I2;\n\nextern int *p, *q;\n\n// Slight modification to prevent linker error\n//struct A { ~A(); };\nstruct A { ~A() {}; };\n\ntypedef A AB;\n\nint main()\n{\n    p->C::I::~I(); // The name I after ~ is looked up in the same scope as I before ::\n                   // (that is, within the scope of C, so it finds C::I)\n\n    q->I1::~I2();  // The name I2 is looked up in the same scope as I1\n                   // (that is, from the current scope, so it finds ::I2)\n\n    AB x;\n    x.AB::~AB();   // The name AB after ~ is looked up in the same scope as AB before ::\n                   // (that is, from the current scope, so it finds ::AB)\n}\n
Run Code Online (Sandbox Code Playgroud)\n

令我惊讶的是,编译没有任何错误。但到底发生了什么

\n
p->C::I::~I();\nq->I1::~I2();\n
Run Code Online (Sandbox Code Playgroud)\n

?这不仅看起来像 it\xe2\x80\x99 访问int变量的成员并以某种方式引用int析构函数,而且pq也是extern没有任何定义的变量。

\n

为什么这种语法是被允许的,它实际上做了什么?

\n

use*_*522 8

\n

并以某种方式引用 int 析构函数,

\n
\n

这些是伪析构函数调用。不使用类型别名的限定查找的直接表示法是

\n
p->~int();\nq->~int();\n
Run Code Online (Sandbox Code Playgroud)\n

如果是标量类型而不是类类型,则符号x.~T()orp->~T()始终是伪析构函数调用。T在这种情况下x必须有 typeTptype int*

\n

伪析构函数调用结束对象x/的生命周期*p,就像普通的析构函数调用一样,但不执行任何其他操作。特别是它不调用任何析构函数(标量类型没有)。它的存在只是为了让人们可以编写适用于类和非类类型的通用代码,而无需调用特殊情况的析构函数。

\n
\n

这不仅看起来像是\xe2\x80\x99s访问int变量的成员

\n
\n

这在评论和链接的 cppreference 文章本身中进行了解释。后跟限定名称的符号并不意味着要查找p->类型的成员。*p相反,根据本文中提供的规则,查找还可以考虑当前范围。但是,如果*p不是类类型,则伪析构函数调用是此类查找的唯一结果,不会导致表达式最终格式错误。

\n
\n

但 p 和 q 也是没有任何定义的外部变量。

\n
\n

伪析构函数调用 odr-usepq,因此程序中必须存在它们的定义。但是,它可能位于不同的翻译单元中。即使它不存在,这样的 odr 违规也会使程序 IFNDR(格式错误,无需诊断),因此编译器不必抱怨它。毕竟,这些行实际上不会导致发出任何机器代码,因此没有理由麻烦链接器来查找p和 的定义q的定义。

\n

  • @nick如果您自己实现某些数据结构,需要对其使用的存储进行强有力的控制,那么您通常需要手动析构函数调用,例如,如果您实现“std::vector”。它需要使用placement-new手动创建对象并使用析构函数调用销毁它们。您希望通用向量支持所有元素类型,因此您不希望对非类类型调用析构函数的逻辑进行特殊处理(我什至不确定在 C++11 `< type_traits>` 的 `std::is_class`)。 (2认同)