1

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

4

3 回答 3

3

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

所以richestBanks并且banks此时已经被初始化了。而且你不能两次初始化一个对象。

richestBanks = MaxHeap(numBanks,bankArr, locs);

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

正确的解决方案是停止做任何你需要locs的事情,并找到更好的方法来构造你的数据,这样你就可以正确使用初始化列表。

于 2013-01-12T18:40:30.853 回答
0
richestBanks = MaxHeap(numBanks,bankArr, locs)

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

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

于 2013-01-12T18:23:59.580 回答
0

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

为在 CentralBank 构造函数的主体中构造的 MaxHeap 和 HashTable 的临时实例调用析构函数,最终超出范围。这些临时变量被复制到成员变量richestBanksandbanks中,这些变量在进入此构造函数的主体时已经初始化。

假设您确实需要 int 指针数组,您可以根据正常的 RAII 指南设置一个辅助类来处理其生命周期。像这样的东西:

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

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

   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的数据结构。

于 2013-01-12T21:14:51.210 回答