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++ の規則により、クラスのすべての基本クラスとクラスのすべてのメンバーが初期化されていることが保証されます。そのため、初期化リストはコンストラクターの本体の外にあります。コンストラクタ本体の前に呼び出されるためです。コンストラクターの初期化リストでコンストラクターとパラメーターを指定しなかった場合、デフォルトで初期化されます。

したがってrichestBanksbanksこの時点ですでに初期化されています。また、オブジェクトを 2 回初期化することはできません。

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 の一時的なインスタンスに対して呼び出され、最後に範囲外になります。これらの一時変数は、このコンストラクターの本体へのエントリで既に初期化されているメンバー変数およびにコピーされます。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)
{}

このようにして、すべてのメンバーが直接初期化され、一時的なコンストラクター本体はまったく必要ありません。

このような外部配列を使用する必要があるかどうかも検討する価値があります。treepとして知られるデータ構造が本当に必要だと思います。

于 2013-01-12T21:14:51.210 に答える