【问题标题】:pointing to a member that has not yet been initialized指向尚未初始化的成员
【发布时间】:2013-03-19 22:46:49
【问题描述】:

我已经问过this 的问题。我现在的问题是这是如何工作的?详细地说,我怎样才能指向一个尚未初始化的对象。我已经制作了这个 MWE,它表明该对象是创建的副本而不是分配的副本。即该对象尚未初始化,但我可以指向它。

#include <iostream>

class Foo {
public:
    int x;

    Foo(const Foo& ori_foo) {
        std::cout << "constructor" << std::endl;
        x = ori_foo.x;
    }

    Foo& operator = (const Foo& ori_foo) {
        std::cout << "operator =" << std::endl;
        x = ori_foo.x;
        return *this;
    }

    Foo(int new_x) {
        x = new_x;
    }
};

class BarParent {
public:
    Foo *p_foo;

    BarParent(Foo* new_p_foo) : p_foo(new_p_foo)
    {
       std::cout << (*new_p_foo).x << std::endl;
    }
};

class BarChild : public BarParent {
public:
    Foo foo;

    BarChild(Foo new_foo)
        :BarParent(&foo) //pointer to member not yet initialised
        ,foo(new_foo) // order of initilization POINT OF INTEREST
        {}
};

int main()  {
    Foo foo(101);

    BarChild bar(foo);

    std::cout << bar.p_foo->x << std::endl;
std::cout << bar.foo.x << std::endl;
}

输出:

constructor
0
constructor
101
101

不要害怕深入了解如何处理内存的细节。而且,每个成员都居住在哪里。

【问题讨论】:

  • 如果还不清楚请告诉我
  • 抱歉有错误现在编辑了:BarParent(&amp;foo)
  • 你试过在 BarParent 构造函数中打印 Foo 的值吗?
  • 你的例子的一个问题是你从来没有真正使用过 bar.p_foo,所以它可以是没有任何问题的任何东西。
  • 我的猜测是,即使成员 Foo 尚未初始化,在调用基本构造函数之前已经为它(以及所有其他成员变量)分配了空间。这将允许您传递指向该空间的指针,即使它未初始化。

标签: c++ pointers inheritance member


【解决方案1】:

不要将初始化误认为是分配。 BarChild::foo 将在调用构造函数之前分配,因为它存储在适当的位置,因此将有一个明确定义的位置供 BarParent::p_foo 指向。 Foo 的构造函数会初始化 BarChild::foo,但只要你在调用构造函数之前不尝试从 BarChild::foo 读取,你就不会注意到顺序。

【讨论】:

  • 如果成员的初始化不依赖其他成员;这段代码使用起来非常好,没有令人不快的惊喜。对吗?
  • @aiao 如果成员在初始化之后才被读取,则它是安全的。这与您所说的略有不同,但在此示例中或多或少相同。
  • 您能否详细说明除了其他成员的初始化之外,还有哪些人可以使用该成员。
  • 另一个线程中的代码可能会使用它,或者来自其他成员的初始化器可能会调用其他可能触及它的代码。需要记住的更重要的一点是, foo 甚至可能没有在构造函数中初始化,它可能是一个仅在特定状态下使用的值,因此仅在对象进入该状态时才被初始化。在这个例子中,这些都不是hte case,所以我认为你是安全的。
【解决方案2】:

在这一行

BarChild bar(foo);

编译器为BarChild 对象保留足够的堆栈空间,然后调用构造函数开始对象的生命周期。在对象内foo 成员有一个固定的偏移量,每个BarChild 对象在它的相同偏移量处都有一个foo 成员,所以由于this 指针在构造函数内有一个已知地址(它是bar 在堆栈上)然后this-&gt;foo 也在一个已知地址,即使该地址的内存尚未初始化。 BarChild obejct 在初始化每个成员时不会“变大”,它的大小是固定的,并且所有成员的空间在初始化之前就已经“保留”了。

这有点类似于:

 char raw_memory[sizeof(Foo)];  // define block of uninitialized memory
 char* addr = raw_memory;       // take address of uninitialized memory
 new (raw_memory) Foo;          // initialize memory

该对象还不存在,使用它是无效的,但是它的地址在它被初始化之前是已知的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-18
    • 1970-01-01
    • 1970-01-01
    • 2016-07-10
    • 1970-01-01
    • 1970-01-01
    • 2022-11-01
    相关资源
    最近更新 更多