我有以下类有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”参数。
答案 0 :(得分:3)
一旦输入构造函数的主体,C ++的规则就可以保证类的所有基类和类的所有成员都已初始化。这就是初始化列表在构造函数体外的原因;因为它在构造函数体之前被调用。如果你没有在构造函数的初始化列表中指定构造函数和参数,那么它将被默认初始化。
因此richestBanks
和banks
已经初始化了。并且您无法初始化对象两次。
richestBanks = MaxHeap(numBanks,bankArr, locs);
这样做是临时创建新 MaxHeap
对象,然后调用复制赋值运算符(或在适当的时候移动赋值)将新数据复制到richestBanks
。在此之后,必须销毁临时对象。这是析构函数,你会看到它。
正确的解决方案是停止执行您需要的任何事情locs
并找到更好的方法来构建数据,以便您可以正确使用初始化列表。
答案 1 :(得分:0)
richestBanks = MaxHeap(numBanks,bankArr, locs)
我记得,这意味着,您创建一个临时对象,运行复制构造函数将其复制到richestBanks变量,然后销毁此临时变量。
更好的解决方案是引用对象(MaxHeap&)而不是对象本身或指针。
答案 2 :(得分:0)
我的问题是堆的析构函数和哈希表在它们的构造函数之后被调用。
正在调用析构函数,以便在CentralBank构造函数的主体中构造MaxHeap和HashTable的临时实例,这些实例最后会超出范围。这些临时值被复制到成员变量richestBanks
和banks
中,这些已经初始化,在进入此构造函数的主体时已经。
假设您确实需要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的数据结构。