初始化构造函数内的对象而不是初始化列表

时间:2013-01-12 18:18:41

标签: c++ constructor initialization destructor

我有以下类有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”参数。

3 个答案:

答案 0 :(得分:3)

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

因此richestBanksbanks已经初始化了。并且您无法初始化对象两次

richestBanks = MaxHeap(numBanks,bankArr, locs);

这样做是临时创建 MaxHeap对象,然后调用复制赋值运算符(或在适当的时候移动赋值)将新数据复制到richestBanks 。在此之后,必须销毁临时对象。这是析构函数,你会看到它。

正确的解决方案是停止执行您需要的任何事情locs并找到更好的方法来构建数据,以便您可以正确使用初始化列表。

答案 1 :(得分:0)

richestBanks = MaxHeap(numBanks,bankArr, locs)

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

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

答案 2 :(得分:0)

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

正在调用析构函数,以便在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的数据结构。