构造函数初始化列出了顺序/分配问题

时间:2010-11-05 17:52:25

标签: c++ constructor

我的问题很简单,下一个代码是安全的吗?

struct Parent {
    B* _a;
    Parent(B* a) : _a(a) {}
};

struct Child : public Parent {
    B _b;
    Child() : Parent(&_b),  _b(2){};
};

int main() {
    Child c;
    return 0;
}

还有两点:

  • 我对将成员对象的引用传递给父对象感兴趣。
  • 安全的我的意思是_b将被分配(及其内存地址),并且无论我使用哪种编译器,此代码都能正常工作。

提前致谢。

澄清
通过安全我实际上意味着内存地址是有效的,因为我已经知道它没有被初始化。

其他说明
在我的实际代码中,我想将类型为B的对象存储为其基类A的指针,如下所示:

struct Parent {
    A* _a;
    Parent(A* a) : _a(a) {}
};

struct Child : public Parent {
    B _b;
    Child() : Parent(&_b),  _b(2){};
};

int main() {
    Child c;
    return 0;
}

如果我理解AndreyT正确回答,那是非法的。我想我会尝试以不同的方式做到这一点,因为这种方法很容易出错。 (我可能会忘记在下一个重构中我无法使用该指针并对其执行某些操作)。

3 个答案:

答案 0 :(得分:8)

在您描述的意义上,是的,它是安全的:内存已分配,将指针传递给父级是完全正确的。 Child::_b的内存实际上是整个Child内存的组成部分。它不需要任何明确的额外“分配”。到调用Child::Child构造函数时,内存显然已存在。

但是,指针指向的内存只能以有限的方式使用(标准在3.8中描述了什么可以和不能用它做什么),因为它指向的对象尚未初始化。在您的具体示例中,您只需存储指针。这完全没问题。

但是,例如,如果您想将该指针转换为某种基类类型(假设B有一些基类),则代码将是非法的。将指向未初始化对象的指针转换为基类指针是非法的(再次参见3.8)。

答案 1 :(得分:6)

初始化顺序如下:

// Base classes:
Parent(&_b)

// Members:
_b(2)

// Constructor Body:
Child() { }

这是否安全取决于您对“安全”的定义。根据你的定义(“它会起作用吗?”),是的,它是安全的。 Child::_b的生存期在创建Child对象时开始,因此您可以获取指向它的指针,该指针指向一个对象。但是,在初始化_b之后,在基类的构造函数Parent返回之后,才能使用指向的值。

答案 2 :(得分:1)

首先调用父构造函数,然后将一个unitiliazed成员变量的地址传递给该构造函数。这不安全。

编辑:

我认为AndreyT更清楚,更生动地说明了我写答案时脑海中出现的问题类型。这些是不能立即察觉的错误类型。那种会让你夜不能寐,试图找出代码中存在悬挂指针的位置或者内存损坏发生的地方。