【问题标题】:Does the lifetime of an array object end when its' element storage is reused?数组对象的生命周期是否在其元素存储被重用时结束?
【发布时间】:2020-09-19 04:33:35
【问题描述】:

在随后的引用中,我指的是 ISO 标准草案 N4713。

第 6.6.3 节第 1 段说:

...类型 T 的对象 o 的生命周期在以下情况下结束:
...
——对象占用的存储被释放,或者被重用 通过不嵌套在 o (6.6.2) 中的对象。

请回答代码cmets中的问题:

#include <new>

int main() {
    int x[2] = {0, 1};
    char* p = new (x + 1) char{0}; // Has x ended its' lifetime?
    int z = x[0];                  // Is this UB?
}

如果我使用 unsigned char 作为数组元素类型,则数组对象 x 将为 *p 提供存储,根据 § 6.6.2 第 3 段:

如果在与 另一个类型为“N unsigned char 数组”或“数组”类型的对象 e N std::byte” (21.2.1),该数组为创建的 对象如果:
— e 的生命周期已经开始但没有结束,并且
- 这 新对象的存储完全适合 e,并且
— 没有 满足这些约束的更小的数组对象。

请验证我在代码 cmets 中的陈述:

#include <new>

int main() {
    unsigned char x[2] = {0, 1};
    char* p = new (x + 1) char{0}; // Only x[1] have ended its' lifetime.
    int z = x[0];                  // This is OK.
}

虽然我不明白前面引用的最后一条规则,但请举个例子?

没有更小的数组对象可以满足这些约束。

【问题讨论】:

  • § 6.6.2,第 3 段指的是unsigned char 的数组或std::byte 的数组。您的示例两者都没有(如果您的数组为 int),因此该部分不适用。
  • 您的设置似乎存在更根本的缺陷。 § 6.6.3 第 1 段规定“不嵌套在其中”,而 § 6.6.2 第 3 段要求“新对象的存储完全适合”。 也就是说,第 6.6.3 节第 1 段适用于一个对象未​​嵌套在另一个对象中的情况,而第 6.6.2 节第 3 段仅适用于一个嵌套在另一个对象中的情况。这两段不能同时适用于您的方案。
  • "虽然我没看懂前面引用的最后一条规则,但请举个例子?" 规范文本后面有例子timsong-cpp.github.io/cppwp/n4861/intro.object#3.example-1
  • 数组的生命周期结束,但int z = x[0]; 似乎不是UB,因为数组到指针的转换和指针运算不需要数组或其元素在其生命周期内。 x[0] 的生命周期并没有结束,因为它的存储没有被重用。
  • @LanguageLawyer > 指针运算不需要数组或其元素在其生命周期内您能指出标准中的规则吗? >并且 x[0] 的生命周期还没有结束,因为它的存储没有被重用你暗示当一个对象结束它的生命周期时,子对象继续存在......标准中是否有规定这种情况的规则?

标签: c++ arrays c++17 language-lawyer lifetime


【解决方案1】:

根据下面的阅读标准,数组的生命周期不是由placement new 表达式结束的:

[basic.life]/1.5:

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

  • [...]

  • 对象占用的存储被释放,或者被未嵌套在 o ([intro.object]) 中的对象重用。

根据这个规则,如果在数组中创建的新对象没有嵌套在数组中,则数组的生命周期结束。否则不会结束。

[intro.object]/2

如果在与成员子对象或数组元素 e 关联的存储中创建对象(可能在也可能不在其生命周期内),则创建的对象是 e 的包含对象的子对象,如果:

  • e 的包含对象的生命周期已经开始但没有结束,并且

  • 新对象的存储正好覆盖与 e 关联的存储位置,并且

  • 新对象与 e 的类型相同(忽略 cv 限定)。

最后两个项目符号没有填满,所以很明显,新的 char 对象不是数组的子对象。

然后[intro.object]/3:

如果在与另一个“N unsigned char 数组”类型或“N std​::​byte 数组”类型的对象 e([cstddef. syn]),该数组为创建的对象提供存储,如果:

  • e 的生命周期已经开始但没有结束,并且

  • 新对象的存储空间完全适合 e,并且

  • 没有更小的数组对象可以满足这些约束。

所以 unsigned char 数组为新的 char 对象提供了存储空间。

[intro.object]/4:

一个对象 a 嵌套在另一个对象 b 中,如果:

  • a 是 b 的子对象,或者

  • b 为 a 提供存储空间,或者

  • 存在一个对象c,其中a嵌套在c中,c嵌套在b中。

正如我们上面提到的,第一个项目符号没有填满。第二个是满的。所以根据[basic.life]/1.5,数组的生命周期并没有结束,因为新的char对象嵌套在数组中:

int main() {
    unsigned char x[2] = {0, 1};
    char* p = new (x + 1) char{0}; // x provides storage for the char object
    int z = x[0];                  // OK The first element is within its lifetime.
}

如果不是这样,可能大部分低级代码都不会符合标准!

【讨论】:

    猜你喜欢
    • 2014-10-28
    • 2013-08-22
    • 2022-11-30
    • 2017-05-31
    • 2012-03-21
    • 2021-04-02
    • 1970-01-01
    • 1970-01-01
    • 2020-12-25
    相关资源
    最近更新 更多