哪些操作会触发给定位置的对象生命周期结束?

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

考虑这个场景:

#include <array>
#include <cstddef>
#include <cstdint>
#include <memory>

struct S {
    alignas(std::uint64_t) alignas(
        std::uint32_t) std::array<std::byte, sizeof(std::uint64_t)> storage = {
        some init values};
};

int main() {
    S s;
    // explicitly creating an uint64_t at the storage location
    std::uint64_t* pi64 =
        std::start_lifetime_as<std::uint64_t>(s.storage.data());
    // explicitly creating an uint32_t at the storage location
    std::uint32_t* pi32 =
        std::start_lifetime_as<std::uint32_t>(s.storage.data());
}

例如,第二个

std::start_lifetime_as
是否足以触发前一个
std::uint64_t
的生命周期结束?
我确信
new (storage.data()) std::byte[std::uint64_t]
会通过明确存储的重用来做到这一点。
还有哪些其他操作可以触发生命周期的终止?

注意,为了简单起见,我使用了普通类型(隐式生命周期类型,普通可破坏),但问题适用于所有类型。

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

哪些操作会触发给定位置的对象生命周期结束?

这在 [basic.life]/1 中定义得非常简洁,在后 C++23 草案 N4950 的版本中引用:

类型 T 的对象 o 的生命周期在以下情况结束:

  • 如果 T 是非类类型,则对象被销毁,或者
  • 如果 T 是类类型,则析构函数调用开始,或者
  • 对象占用的存储被释放,或者被未嵌套在o([intro.object])内的对象重用。

例如,第二个 std::start_lifetime_as 是否足以触发前一个 std::uint64_t 的生命周期结束?

是的,因为

std::start_lifetime_as
被定义为隐式创建对象,包括一个指定类型的对象 ([obj.lifetime]/3) 并返回指向该特定对象的指针 ([obj.lifetime]/4) )。

创建新的

uint32_t
对象会结束前一个
uint64_t
对象在存储中重叠的生命周期,因为第一个引用中的最后一项是存在的,因为新对象不能嵌套
uint64_t
对象中。

顺便说一句,这也适用于第一个

start_lifetime_as
。它将创建一个新的
uint64_t
对象,与
S s;
变量定义中创建的第一个对象完全重叠。这个新的
uint64_t
对象(与后来的
uint32_t
对象相比)可以与旧对象进行透明替换,因此可以有效地使用它,就好像这两个对象是相同的一样。 (参见[basi.life]/8

任何显式或隐式创建对象的操作都会产生这种效果。您提到了 place-new 显式创建了一个新对象。其他可以“潜在”创建新对象的操作是指定隐式创建对象的函数,例如 std::memcpy/

std::memmove
结束生命周期的另一种方法是使用伪析构函数调用:

s.storage.data().~uint64_t();

此处第一个引用中列表中的第一项将适用。

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