正在构造函数内部初始化对象,而不在初始化列表中

Initializing an object inside the constructor and not in initialization list

本文关键字:初始化 列表 对象 构造函数 内部      更新时间:2023-10-16

我有一个包含3种数据类型的类:

   class CentralBank{
    MaxHeap richestBanks;
    HashTable banks;
    AccountTree accounts;
public:
    CentralBank(int numAccounts, Account* accounts, int numBanks, Bank* bankArr);
    void AddAccount(Account account);
    void RemoveAccount(int accountID);
    void AddBank(Bank bank);
    int GetAccountsNumber(int bankID);
    void GetKRichestBanks(unsigned int K, Bank* banks);
    int GetSumBalance (int low, int high);
};

这是构造函数:

CentralBank::CentralBank(int numAccounts, Account* accounts, int numBanks,
        Bank* bankArr): accounts(numAccounts,accounts){
    int** locs = new int*[numBanks];
    richestBanks = MaxHeap(numBanks,bankArr, locs);
    banks = HashTable(numBanks,bankArr,locs);
    delete[] locs;
}

我的问题是堆和哈希表的析构函数是在它们的构造函数之后调用的。如果我把它们都变成指针,那就不会发生。为什么会发生这种情况?有没有办法让它们不成为指针,也不在初始化后立即调用析构函数?我没有正确初始化它们吗?

PS:它们不在初始化列表中,因为它们的构造函数需要"locs"参数,该参数需要初始化。

一旦输入构造函数的主体,C++的规则就保证该类的所有基类和该类的全部成员都已初始化。这就是为什么初始化列表在构造函数的主体之外;因为它在构造函数主体之前被调用。如果您没有在构造函数的初始化列表中指定构造函数和参数,那么它将被默认初始化。

因此CCD_ 1和CCD_。并且您不能初始化对象两次

richestBanks = MaxHeap(numBanks,bankArr, locs);

这样做的目的是临时创建一个新的MaxHeap对象,然后调用复制分配运算符(或移动分配,如果适用(将新数据复制到richestBanks中。在此之后,必须销毁临时对象。这就是你看到的析构函数调用。

正确的解决方案是停止执行任何需要locs的操作,并找到一种更好的方法来构造数据,以便正确使用初始化列表。

richestBanks = MaxHeap(numBanks,bankArr, locs)

我记得,这意味着创建一个临时对象,运行复制构造函数将其复制到richestBanks变量,然后销毁这个临时变量。

更好的解决方案是引用对象(MaxHeap&(,而不是对象本身或指针。

我的问题是堆和哈希表的析构函数是在它们的构造函数之后立即调用的

正在为在CentralBank构造函数的主体中构造的MaxHeap和HashTable的临时实例调用析构函数,这些实例最终超出了作用域。这些临时变量被复制到成员变量richestBanksbanks中,这两个变量在进入该构造函数的主体时已被初始化。

假设您确实需要int指针数组,那么您可以根据正常的RAII准则设置一个辅助类来处理它的生存期。类似这样的东西:

class IntPointerArray
{
public:
    IntPointerArray( int num )
    : array_(new int*[num])
    {}
    ~IntPointerArray()
    { delete [] array_; }
    operator int** ()
    { return array_; }
private:
    int** array_;
};

现在,扩展您的类以将其实例作为成员:

   class CentralBank{
    IntPointerArray locs;
    MaxHeap richestBanks;
    HashTable banks;
    AccountTree accounts;
    // rest omitted

根据成员按照声明的顺序初始化的规则,您的构造函数现在可以如下所示:

CentralBank::CentralBank(int numAccounts, Account* accounts, int numBanks, Bank* bankArr)
: locs(numBanks)
, richestBanks(numBanks,bankArr, locs) // exploits operator int**
, banks(numBanks,bankArr, locs) // ditto
, accounts(numAccounts,accounts)
{}

通过这种方式,所有成员都被直接初始化,并且根本不需要具有临时性的构造函数体。

是否应该使用这样的外部数组也值得研究。我猜你真的需要被称为treap的数据结构。