- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
下面的代码合法吗?
struct S
{};
int main()
{
S* p = new S;
p->~S();
delete p;
}
标准规则位于 [basic.life#6] :
Before the lifetime of an object has started but after the storage which the object will occupy has been allocated24 or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that represents the address of the storage location where the object will be or was located may be used but only in limited ways. For an object under construction or destruction, see [class.cdtor]. Otherwise, such a pointer refers to allocated storage ([basic.stc.dynamic.allocation]), and using the pointer as if the pointer were of type void* is well-defined. Indirection through such a pointer is permitted but the resulting lvalue may only be used in limited ways, as described below. The program has undefined behavior if:
(6.1) — the object will be or was of a class type with a non-trivial destructor and the pointer is used as the operand of a delete-expression,
(6.2) — the pointer is used to access a non-static data member or call a non-static member function of the object
[basic.life#6.1] 不适用,所以这段代码似乎是合法的,因为 S
有一个普通的析构函数。
然而,根据[basic.life#6.2],这段代码是非法的,因为delete-expression调用了S
对象的析构函数,这是它的一个非静态成员函数。
编辑:根据[class.dtor#19] ,也是违法的。
我应该听什么?可能 [basic.life#6.2],因为 [basic.life#6.1] 没有规定对于具有平凡析构函数的类这样做必须是合法的。
结论是不合法。
但是,将 S
替换为标量类型后,情况似乎有所不同:
#include <memory>
int main()
{
char* p = new char;
std::destroy_at(p);
delete p;
}
根据[expr.call#5],这将对p
指向的char
对象进行伪析构函数调用,这将结束其生命周期。 :
If the postfix-expression names a pseudo-destructor (in which case the postfix-expression is a possibly-parenthesized class member access), the function call destroys the object of scalar type denoted by the object expression of the class member access ([expr.ref], [basic.life]).
[basic.life#6.1] 仍然不适用。
但不同的是 [basic.life#6.2] 也不适用,因为没有为 char
对象调用非静态成员函数 (char
毕竟不是一个类)。
结论是合法的。
为什么?
最佳答案
好像是措辞有问题。您的代码要么是合法的,要么不是。如果它是合法的,那么 [basic.life]/6.2 应该有一个普通析构函数的异常(exception)。如果它不是合法的,那么应该从 [basic.life]/6.1 中删除“使用非平凡的析构函数”这句话,因为即使析构函数是平凡的,不可避免的析构函数调用也会违反 p6.2。
我怀疑它是合法的,因为在 delete
的情况下保留显式异常是没有意义的,如果不是为了防止破坏实际上调用 的代码对具有超出其生命周期的普通析构函数的对象删除
。
N2762删除了所有其他导致 UB 的指针操作的普通析构函数异常,这些操作指向超出其生命周期的对象的指针,但明显保留它用于 delete-expression。这表明需要在语言中保留此异常以避免破坏代码。
最有可能的原因是为什么第二个项目符号没有也被更改为一个普通的析构函数调用的异常(exception)是作者忘记了一个delete-expression确实调用析构函数,即使它是微不足道的。他们可能假设 delete
被指定为跳过微不足道的析构函数调用。
(另请注意,在 C++98 到 C++17 中,S
对象的生命周期不会因析构函数调用而结束,因为 [basic.life]/1 指定析构函数调用仅当对象不平凡时才结束对象的生命周期;这在 C++20 中由 CWG2256 更改。但是,由于 N2762,在 C++11 及更高版本中,如果对象的生命周期尚未 started 因为它具有重要的初始化,我们可能会遇到与 OP 描述的问题类似的问题。)
我认为就此提交一份缺陷报告是值得的,尽管我不确定结果会是什么。自 N2762 以来已经过去了这么多时间,我想委员会实际上会考虑此时是否应该消除平凡析构函数的异常(即,修复 p6.1 而不是 p6.2 );毕竟,CWG2256 的决议也可能破坏了一些代码,但自从 C++ 从 C 中分离出来以来,这种代码可能已经变得越来越少了。
关于c++ - 在指向类类型对象的指针上使用 delete-expression 的合法性,其生命周期已结束的平凡析构函数/标量类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73434558/
既然将两个指针相加是非法的,那么这段代码如何有效? struct key *low = &tab[0]; struct key *high = &tab[n]; struct key *mid; wh
我怎样才能完成以下建议的内容?: template class Base{...}; ... class Derived : public Base{...}; 最佳答案 是的,这是合法的。 Base
关闭。 这个问题不符合 Stack Overflow guidelines 。它目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 关闭 5 年前。 Improve
我是一名优秀的程序员,十分优秀!