在C ++中放置派生的新基础子对象 [英] Placement new base subobject of derived in C++

查看:202
本文介绍了在C ++中放置派生的新基础子对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否定义了行为以放置新的派生对象的可轻易破坏的基础对象?

Is it defined behavior to placement-new a trivially destructible base object of a derived?

struct base { int& ref; };
struct derived : public base {
    complicated_object complicated;
    derived(int& r, complicated_arg arg) :
            base {r}, complicated(arg) {}
};

unique_ptr<derived> rebind_ref(unique_ptr<derived>&& ptr,
                               int& ref) {
    // Change where the `ref` in the `base` subobject of
    // derived refers.
    return unique_ptr<derived>(static_cast<derived*>(
        ::new (static_cast<base*>(ptr.release()) base{ref}));
}

请注意,我试图构造rebind_ref的目的是不破坏编译器可能做出的任何严格的别名假设.

Note that I tried to structure rebind_ref to not break any strict aliasing assumptions a compiler might have made.

推荐答案

否,出于至少两个原因,C ++标准不允许这样做.

No, this is not allowed by the C++ Standard, for at least two reasons.

有时在

The text that sometimes allows a placement-new of a new object into the storage for another object of the same type is found in [basic.life], paragraph 8. The bold emphasis is mine.

如果在对象的生命周期结束之后且在重新使用或释放​​该对象所占用的存储之前,在原始对象所占用的存储位置上创建了一个新对象,该对象指向原始对象,引用原始对象的引用或原始对象的名称将自动引用新对象,并且一旦开始新对象的生存期,就可以使用它来操作新对象,如果:

If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if:

  • 新对象的存储空间正好覆盖了原始对象所占据的存储位置,并且

  • the storage for the new object exactly overlays the storage location which the original object occupied, and

新对象与原始对象具有相同的类型(忽略顶级cv限定词),并且

the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and

原始对象的类型不是const限定的,并且,如果是类类型,不包含类型为const限定或参考类型

the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type, and

[C ++ 17],原始对象是类型为T最派生对象,而新对象是类型为T的最派生对象(即,它们是不是基类的子对象).

[C++17] the original object was a most derived object of type T and the new object is a most derived object of type T (that is, they are not base class subobjects).

[C ++ 20草稿2018-10-09] 原始对象和新对象都不是潜在重叠的子对象([intro.object]).

[C++20 draft 2018-10-09] neither the original object nor the new object is a potentially-overlapping subobject ([intro.object]).

C ++ 20的更改是为了考虑零大小的非静态数据成员的可能性,但是它仍然排除了所有基类子对象(是否为空)的可能性. 可能重叠的子对象";是 [intro.object]第7 段中定义的新术语:

The C++20 change is to account for the possibility of zero-size non-static data members, but it still also rules out all base class subobjects (empty or not). "Potentially-overlapping subobject" is a new term defined in [intro.object] paragraph 7:

可能重叠的子对象为:

  • 基类子对象,或

使用no_unique_address属性([dcl.attr.nouniqueaddr])声明的非静态数据成员.

a non-static data member declared with the no_unique_address attribute ([dcl.attr.nouniqueaddr]).

(即使您确实找到某种方法来重新安排内容来避免引用成员和基类问题,也要记住确保没有人能够定义const derived变量,例如,通过将所有构造函数设为私有!)

(Even if you do find some way to rearrange things to avoid the reference member and base class issues, remember to make sure nobody can ever define a const derived variable, for example by making all constructors private!)

这篇关于在C ++中放置派生的新基础子对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆