相关疑难解决方法(0)

什么时候为对象设置虚拟表指针(在C++中)?

我知道对于任何具有虚函数的类或者从具有虚函数的类派生的类,编译器会做两件事.首先,它为该类创建一个虚拟表,然后,它将虚拟指针(vptr)放在该对象的基础部分中.在运行时,此vptr被分配并在对象实例化时开始指向正确的vtable.

我的问题是,在实例化过程中,这个vptr的确切位置是什么?这个vptr的赋值是否发生在构造函数之前/之后的对象的构造函数中?

c++ constructor virtual-functions vtable vptr

8
推荐指数
2
解决办法
6494
查看次数

不死对象 ([basic.life]/8):为什么允许引用重新绑定(和常量修改)?

“亡灵”条款

我将不死子句称为 C++ 规则,即在对象销毁后,如果在同一地址创建新对象,有时可以将其视为与旧对象相同的对象。该规则始终存在于 C++ 中,但对附加条件进行了一些更改。

这个问题让我阅读了最新的不死条款。Lifetime [basic.life]/8中修改后的条件是:

(8.1) 新对象的存储正好覆盖原对象所占用的存储位置,并且

嗯,呵呵。位于不同地址的对象不会是同一个对象。

(8.2) 新对象与原始对象的类型相同(忽略顶级 cv 限定符),以及

再说一遍,呵呵。

(8.4) 原始对象和新对象都不是潜在重叠的子对象 ([intro.object])。

它不能是基类、经典类(或具有使其地址不唯一的特殊声明的成员)。再说一遍,呵呵。

(8.3) 原始对象既不是 const 限定的完整对象,也不是此类对象的子对象,并且

现在这很有趣。被替换的对象不能是:

  • 一个完整的 const 对象
  • 完整 const 对象的一部分

另一方面,被复活的对象可以是:

  1. const 成员子对象
  2. 这种 const 成员的子对象
  3. const 对象数组中的一个元素

常量子对象

所以在我看来,所有这些对象x都可以复活:

常量成员子对象

struct CI {
  const int x;
};

CI s = { 1 };
new ((void*)&s.x) int(2);
int r = s.x; // OK, 2
Run Code Online (Sandbox Code Playgroud)

const 成员的子对象:

struct T {
  int x;
};

struct CT …
Run Code Online (Sandbox Code Playgroud)

c++ constants lifetime placement-new language-lawyer

6
推荐指数
1
解决办法
148
查看次数

用相同类型的对象覆盖对象

以下是否定义明确?

#include <iostream>
#include <string.h>

using namespace std;

struct Const {
    const int i; 
    Const (int i) : i(i) {}
    int get0() { return 0; } // best accessor ever!
};

int main() {
    Const *q,*p = new Const(1);
    new (p) Const(2);
    memcpy (&q, &p, sizeof p);
    cout << q->i;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

注意,在构造第二个之后Const,p在语义上(故意?)指向新对象,并且第一个已经消失,因此它可以"用作void*".但是第二个对象是在完全相同的地址构造的,因此位模式p表示新对象的地址.

评论

new (p) Const(2)擦除存储在的旧对象p,因此指针不再有效,除非作为指向storage(void*)的指针.

我想恢复p作为一个的价值Const*.

评论2

在任何一个p->~Const()或 …

c++ const placement-new memcpy language-lawyer

4
推荐指数
1
解决办法
304
查看次数

指向派生类的指针的“static_cast&lt;Base*&gt;(static_cast&lt;void*&gt;(衍生))”何时有效?

对于这个问题,不涉及多态性,即不涉及虚方法,不涉及虚基类。以防万一,我的案子不涉及其中任何一个。

假设我有一个类Derived,它有一个明确的可访问父类型Base,没有多态性(没有虚拟方法,没有虚拟基类),但可能涉及间接和/或多继承。进一步假设我有一个有效的指针Derived *derived (指向类型Derived或其子类的对象)。

在这种情况下,我相信static_cast<Base*>(derived)是有效的(产生有效的可用指针)。Base当和之间的祖先链Derived涉及多重继承时,这static_cast可能意味着指针调整以在实例Base内定位实例Derived。为此,编译器需要知道继承链,在本例中他就是这样做的。但是,如果插入了中间转换void *,则编译器将隐藏该继承链信息。对于哪个继承链来说,这样的静态转换仍然有效?我期望以下之一:

  • 一个都没有?访问static_castfrom void 指针是未定义的行为,除非该指针确实指向确切的类型。
  • 对于所有没有多重继承的链?然后,编译器可以保证Base始终位于Derived- 但标准怎么说?
  • 对于所有链,Base在所有中间多重继承链的第一个父类中可以找到什么?Base也许和的开始Derived仍然匹配?
  • 总是?static_castto void 指针始终可以调整到第一个父级的开头,而static_castfrom void 指针则撤消该调整。但对于多重继承,“第一个父母”不一定是所有父母的父母。

c++ inheritance static-cast upcasting

1
推荐指数
1
解决办法
496
查看次数

指针变量只是与某些运算符整数还是"符号"?

编辑:原始的单词选择令人困惑.术语"象征性"比原始术语("神秘")要好得多.

在关于我以前的C++问题的讨论中,我被告知指针是

这并没有健全的权利!如果没有任何符号,并且指针是其表示,那么我可以执行以下操作.我可以吗?

#include <stdio.h>
#include <string.h>

int main() {
    int a[1] = { 0 }, *pa1 = &a[0] + 1, b = 1, *pb = &b;
    if (memcmp (&pa1, &pb, sizeof pa1) == 0) {
        printf ("pa1 == pb\n");
        *pa1 = 2;
    }
    else {
        printf ("pa1 != pb\n");
        pa1 = &a[0]; // ensure well defined behaviour in printf
    }
    printf ("b = %d *pa1 = %d\n", …
Run Code Online (Sandbox Code Playgroud)

c++ pointers undefined-behavior language-lawyer

-2
推荐指数
1
解决办法
462
查看次数

取消引用50%的出界指针(数组数组)

这是我在"我不理解C和C++中的指针"集合中的一个新问题.

如果我将具有相同值的两个指针的位混合(指向相同的存储器地址),那恰好具有完全相同的位表示,当一个是可解除引用且一个是结束时,标准说应该发生什么?

#include <stdio.h>
#include <string.h>
#include <assert.h>

// required: a == b
// returns a copy of both a and b into dest 
// (half of the bytes of either pointers)
int *copy2to1 (int *a, int *b) {
    // check input: 
    // not only the pointers must be equal
    assert (a == b);
    // also the representation must match exactly
    int *dest;
    size_t s = sizeof(dest);
    assert(memcmp(&a, &b, s) == 0); 

    // copy a and b into dest:
    // …
Run Code Online (Sandbox Code Playgroud)

c c++ arrays pointers language-lawyer

-2
推荐指数
1
解决办法
1272
查看次数