gpt4 book ai didi

c++ - 派生类中基构造函数的控制,潜在的双重初始化

转载 作者:行者123 更新时间:2023-11-28 02:01:46 25 4
gpt4 key购买 nike

关于 this question and the answer to it似乎确实有异常(exception),但它对我提出的问题多于回答问题。考虑一下:

#include <iostream>
using namespace std;
struct base {
virtual void test() {cout << "base::test" << endl;}
base() {test();}
virtual ~base() {}
};
struct derived : base {
virtual void test() {cout << "derived::test" << endl;}
derived() : base() {}
~derived() {}
};
int main() {
derived d;
return 0;
}

我天真地认为这只会打印两条消息中的其中一条。它实际上打印两者 - 首先是基本版本,然后是派生版本。这在 -O0-O3 设置上表现相同,因此据我所知,这不是优化或缺乏优化。

我是否理解在 derived 构造函数中调用 base(或更高/更早类的构造函数)不会阻止默认的 base 构造函数(或其他)不会被预先调用?

也就是说,上面代码片段中构造derived对象的顺序是:base() then derived() and又在那个 base() 里?

我知道仅仅为了调用 base::base() 而修改 vtable 是没有意义的,回到 derived::derived() 之前的状态 被调用,只是为了调用不同的构造函数。我只能猜测与 vtable 相关的东西被硬编码到构造函数链中,并且调用以前的构造函数实际上被解释为正确的方法调用(直到到目前为止在链中构造的最派生对象)?

抛开这些小问题,它提出了两个重要的问题:

<强>1。在派生构造函数中调用基构造函数是否总是会在首先调用派生构造函数之前调用默认基构造函数?这不是低效吗?

<强>2。根据#1,是否有默认基构造函数不应该用于代替在派生类的构造函数中显式调用的基构造函数的用例?这在 C++ 中如何实现?

我知道 #2 听起来很傻,毕竟如果你可以推迟调用基类构造函数直到任意函数调用,你就无法保证派生类的基类部分的状态是“准备好”/“已构造”在派生的构造函数中。例如这个:

derived::derived() { base::base(); }

...我希望以相同的方式运行并调用基本构造函数两次。然而,编译器似乎将其视为与此相同的情况有什么原因吗?

derived::derived() : base() { }

我不确定。但就观察到的效果而言,这些似乎是等价的陈述。这与我的想法背道而驰,即基本构造函数可以转发(至少在某种意义上),或者可能在使用 :base() 语法的派生类。实际上,该表示法要求将基类放在与派生类不同的成员之前...

换句话说 this answer and it's example (暂时忘记它的 C#)会调用基本构造函数两次吗?虽然我理解它为什么会这样做,但我不明白为什么它不表现得更“直观”并选择基本构造函数(至少对于简单的情况)并只调用它一次。

这不是双重初始化对象的风险吗?或者是在编写构造函数代码时假设对象未初始化的部分内容?最坏的情况我现在必须假设每个类成员都可能被初始化两次并防范这种情况吗?

我将以一个可怕的例子结束——但这不会泄漏内存吗?应该预计会泄漏吗?

#include <iostream>
using namespace std;
struct base2 {
int * member;
base2() : member(new int) {}
base2(int*m) : member(m) {}
~base2() {if (member) delete member;}
};
struct derived2 : base2 {
derived2() : base2(new int) {
// is `member` leaking?
// should it be with this syntax?
}
};
int main() {
derived2 d;
return 0;
}

最佳答案

but would this not leak memory? should it be expected to leak?

没有。操作顺序将是:

derived2::derived2()
auto p = new int
base2::base2(p)
base2::member = p

对于析构函数:

derived2::~derived2() (implied)
base2::~base2()
if (base2::member) { delete base2::member; }

一新一删。完美。

不要忘记编写正确的赋值/复制构造函数。

关于c++ - 派生类中基构造函数的控制,潜在的双重初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39211214/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com