C++ 标准的哪一部分禁止双重销毁和在不销毁的情况下重用存储?

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

现代 C++ 标准(C++20 或 C++23 都可以)的哪些部分规定使用放置 new 和显式析构函数调用来执行以下操作是不行的?

  1. 双重析构函数调用

    alignas(T) std::byte storage[sizeof(T)];
    T* const p = new (storage) T(...);
    p->~T();
    p->~T();
    
  2. 重用存储而不运行析构函数

    alignas(T) std::byte storage[sizeof(T)];
    T* p = new (storage) T(...);
    p = new (storage) T(...)
    p->~T();
    

此外,如果

T
有一个简单的析构函数,这些是否被允许,以及标准的哪些附加部分与该问题相关?


我发现这个之前的答案是一个半相关的问题,它给出了问题(1)的简单析构函数部分的相对清晰的答案,但它使用C ++ 17,令我惊讶的是C ++中的措辞20 似乎已经更改为也禁止微不足道的析构函数这样做。对于琐碎的析构函数来说,这似乎应该没问题,所以我怀疑我错过了一些东西。

c++ language-lawyer c++20 c++23
1个回答
0
投票

1。双重析构函数调用

[basic.life]/6.2

...对象的生命周期结束后...程序具有未定义的行为,如果:

—指针用于...调用对象的非静态成员函数

现在析构函数是非静态成员函数吗?是的,

[class.mem.special]/1

...或者,如果这是一个 伪析构函数调用 (即,如果

T
是非类),那么出于不同的原因它是 UB。
[expr.call]/4
表示它结束了对象的生命周期,如果没有对象(因为它的生命周期已经结束),则前提条件为 false,因此行为未定义。

这对于琐碎的析构函数来说似乎应该没问题,所以我怀疑我错过了一些东西。

́\_(ツ)_/́

2。重用存储而不运行析构函数

似乎是合法的,并且无法证明是否定的(缺乏UB)。

我们所拥有的只是

[basic.life]/1.5
:

..

o
类型的对象
T
的生命周期结束于:

—对象占用的存储空间...被重用

这里没有任何内容表明这是非法的。

此外,如果

T
有一个简单的析构函数,这些是否被允许,以及标准的哪些附加部分与该问题相关?

似乎没有改变任何事情。

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