c++ - 为什么这会创建两次数据对象?

标签 c++

我最近遇到了以下问题,不幸的是,我无法理解为什么在以下代码中创建了两次数据对象。

我认为一旦 _data = i 在 Base(_data = i ) 中执行,它将在 Derived 被销毁之前可用,但正如输出所示,情况并非如此。

希望能有一个合乎逻辑的解释来帮助我理解这个概念。

struct Data
{
    Data(int i_ = 0 ) : _i(i_) { cout << "Inside Data::ctor" << endl; }
    ~Data() { cout << "Inside Data::dtor" << endl ; }

    int _i;
};

struct Info
{
    Info(Data* d_)
    {
            cout << "Inside Info::ctor" << endl;
            cout << d_->_i << endl ;
            d_->_i = 1;
    }

};

struct Base
{
    Base(const Data& data_)
    {
            cout << "Inside Base::ctor" << endl;
            cout << data_._i << endl;
    }
};

struct Derived : public Base
{
    Derived(int i_) : _info(&_data), Base(_data = i_)
    {
            cout << "Inside Derived::ctor" << endl;
            cout << _data._i << endl ;
    }

    Data _data;
    Info _info;
};

int main()
{
    Derived d(100);

    return 0;
}

输出是:

Inside Data::ctor
Inside Base::ctor
100
Inside Data::dtor
Inside Data::ctor
Inside Info::ctor
0
Inside Derived::ctor
1
Inside Data::dtor

最佳答案

注意这里:

Derived(int i_) : _info(&_data), Base(_data = i_)

编译器可能生成了一个您忽略的警告。
不要忽略警告,它们是代码中的逻辑错误。

构造器总是会按照以下顺序调用构造器:

  • 首先调用 Base() 作为基础构造函数:
  • data() 先声明
  • info() 这总是最后调用的。

这部分:

Base(_data = i_)

实际上是调用对 UN 的赋值 - 已初始化的成员,因为 i_ 是一个整数,它在赋值之前首先调用 data() 的默认构造函数(从而生成您的第一个打印语句)。

这部分:

info(&_data)

此处您传递的是技术上未初始化对象的地址(尽管它是非法初始化的(如上所述))。虽然传递未初始化对象的地址可能不是非法的,但这是一个坏主意,因为您传递它的对象也不知道它没有被正确初始化,因此任何用法都是 UB。

因此您的输出描述为:

Inside Data::ctor         // _data = i_; use i to create temporary object to assign to data.    
Inside Base::ctor         // Base Class constructor
100
Inside Data::dtor         // The temporay object (see above) is destroyed
Inside Data::ctor         // The member _data is initialized
Inside Info::ctor         // The member _info is initialized

关于c++ - 为什么这会创建两次数据对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6084962/

相关文章:

c++ - 从任何内存地址读取 UInt32 的最有效方法?

c# - 在多线程应用程序中使用带有媒体基础接口(interface)的 P/Invoke 发生 AccessViolationException

c++ - 链接 src/与 CMake 作为库#include'd 与一些 `libname/` 前缀

c++ - 经典 ASP 和 ITaskScheduler 访问被拒绝错误

c++ - 指针右侧的调用约定属性

c++ - 复杂/ double 类型的运算符重载 "+"

c++ - 在 OSX 和 Linux 之间共享 C++ 程序?

c++ - 如何间接调用 C 函数

c++ 字符串数组初始化

c++ - 可变参数模板参数的模板类型数组