c++ - 是否允许在 Base 的实例上编写 Derived 的实例?

标签 c++ memory overwrite language-lawyer

说吧,代码

    class Derived: public Base {....}

    Base* b_ptr = new( malloc(sizeof(Derived)) ) Base(1);
    b_ptr->f(2);
    Derived* d_ptr = new(b_ptr) Derived(3);
    b_ptr->g(4);
    d_ptr->f(5);

似乎是合理的,LSP很满意。

我怀疑当 Base 和 Derived 是 POD 时,此代码是标准允许的,否则是不允许的(因为 vtbl ptr 被覆盖)。我的问题的第一部分是:请指出这种覆盖的准确先决条件。

可能存在其他标准允许的覆盖方式。

我的问题的第二部分是:还有其他方法吗?他们的确切先决条件是什么?

更新:我不想写这样的代码;我对这种代码的理论可能性(或不可能)感兴趣。所以,这是“标准纳粹”问题,而不是“我怎么能……”的问题。 (我的问题要移到其他 stackoverflow 站点吗?)

更新 2 和 4:关于析构函数呢?这段代码的假定语义是“基本实例由派生实例的切片(破坏性地)更新”。为了简单起见,让我们假设 Base 类有一个普通的析构函数。

更新3:对我来说最有趣的是通过b_ptr->g(4)访问的有效性

最佳答案

你确实需要在 Derived 的 placement-new 之后执行 b_ptr = d_ptr,以防 Base 子对象不是第一个Derived 的布局。如所写,b_ptr->g(4) 会引发未定义的行为。

规则(3.8 basic.life):

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
  • the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and
  • 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
  • the original object was a most derived object (1.8) of type T and the new object is a most derived object of type T (that is, they are not base class subobjects).

您可能还应该在重新使用旧对象的内存之前销毁它,但标准并没有强制要求这样做。但是,如果不这样做,将泄漏旧对象拥有的所有资源。完整规则在标准的第 3.8 节 (basic.life) 中给出:

A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly calling the destructor for an object of a class type with a non-trivial destructor. For an object of a class type with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a delete-expression (5.3.5) is not used to release the storage, the destructor shall not be implicitly called and any program that depends on the side effects produced by the destructor has undefined behavior.

关于c++ - 是否允许在 Base 的实例上编写 Derived 的实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9117358/

相关文章:

c++ - 从 double 转换到 size_t 会产生错误的结果?

java - 在Java中存储和比较大量字符串

javascript - localStorage 不断覆盖我的数据

javascript - AngularJS 指令数据被覆盖

c++ - C++中的点和线类?

c++ - 在 64 位机器上,我可以安全地并行操作 64 位四字的各个字节吗?

c++ - C++检测输入是否不满足条件

c - 在 L1 缓存 : only getting 62% 中获取 Haswell 上的峰值带宽

java - 如何避免 java.lang.OutOfMemoryError : bitmap size exceeds VM budget in android while using a large bitmap?

javascript - jQuery 插件函数覆盖