在现有的 T 对象上放置新的 U 并操纵它是 UB?

发布于 2025-01-11 11:14:22 字数 1628 浏览 0 评论 0原文

在此链接中,存储重用部分显示以下示例。

void x()
{
    long long n; // automatic, trivial
    new (&n) double(3.14); // reuse with a different type okay
} // okay

此处,其中一个答案包含此代码。

void f(float* buffer, std::size_t buffer_size_in_bytes)
{
    double* d = new (buffer)double[buffer_size_in_bytes / sizeof(double)];

    // we have started the lifetime of the doubles.
    // "d" is a new pointer pointing to the first double object in the array.        
    // now you can use "d" as a double buffer for your calculations
    // you are not allowed to access any object through the "buffer" pointer anymore since the // floats are "destroyed"       
    d[0] = 1.;
    // do some work here on/with the doubles...

    // ...
}

以上所有代码都试图在现有对象上执行放置新的另一种类型,第二个代码正在操作新对象。

但是,第一个链接说的是以下内容

如果在另一个对象占用的地址处创建一个新对象,则所有指针, 引用,原始对象的名称将自动引用新对象,并且, 一旦新对象的生命周期开始,就可以用来操作新对象,但前提是 原始对象可以透明地被新对象替换。

如果满足以下条件,则对象 x 可以透明地被对象 y 替换:

  • y 的存储位置恰好覆盖 x 占用的存储位置
  • y 与 x 具有相同类型(忽略顶级 cv 限定符)

强调一句,第二个例子是未定义行为,因为新对象类型与旧对象类型不同,d[0] = 1.;操作新对象。
但是,没有人在评论中指出这个问题......所以我很困惑。

  1. 第一个示例定义的行为是因为它只是执行新的放置吗?
  2. 第二个例子是因为UB的原因而错误的吗?

我是不是误会了什么..?

In this link, Storage reuse section shows the following example.

void x()
{
    long long n; // automatic, trivial
    new (&n) double(3.14); // reuse with a different type okay
} // okay

and here, one of the answers contains this code.

void f(float* buffer, std::size_t buffer_size_in_bytes)
{
    double* d = new (buffer)double[buffer_size_in_bytes / sizeof(double)];

    // we have started the lifetime of the doubles.
    // "d" is a new pointer pointing to the first double object in the array.        
    // now you can use "d" as a double buffer for your calculations
    // you are not allowed to access any object through the "buffer" pointer anymore since the // floats are "destroyed"       
    d[0] = 1.;
    // do some work here on/with the doubles...

    // ...
}

All the above are trying to perform placement new another type on the existing object, and the second code is manipulating the new object.

But, the first link is saying the following

If a new object is created at the address that was occupied by another object, then all pointers,
references, and the name of the original object will automatically refer to the new object and,
once the lifetime of the new object begins, can be used to manipulate the new object, but only if
the original object is transparently replaceable by the new object.

Object x is transparently replaceable by object y if:

  • the storage for y exactly overlays the storage location which x occupied
  • y is of the same type as x (ignoring the top-level cv-qualifiers)

According to the emphasized sentence, the second example is undefined behavior because the new object type is not the same as the old one, and d[0] = 1.; manipulates the new object.
But, no one stated this problem in the comments.. so I'm confused.

  1. Is the first example defined behavior because it just performs placement new?
  2. Is the second example wrong because of UB?

Am I misunderstanding something..?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

楠木可依 2025-01-18 11:14:22

这两个例子都是合法的。

仅当您想要使用指向旧对象的指针来访问新对象而无需 std::launder 时,“透明可替换性”才有意义。

但你没有这样做。您使用 Placement-new 返回的指针(而不是指向旧对象的指针)来操作新对象,它永远不需要 std::launder

Both examples are legal.

"Transparent replaceability" only matters when you want to use a pointer to the old object to access the new object without std::launder.

But you're not doing that. You're manipulating the new object using the pointer returned by placement-new (not a pointer to the old object), which never needs std::launder.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文