4

クラスの()演算子をオーバーロードして、並べ替え比較関数として使用しました。std::sort()を使用すると、何らかの理由でクラスのデストラクタが何度も呼び出されます (明らかに、ベクトル内のエントリの量に依存します)。~RANK() で詳しく説明しました。

#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <algorithm>

class RANK
{
    struct COMBO
    {
        int x;
    };

    std::vector<COMBO *> data;
public:
    RANK()
    {
        printf("RANK()\n");
    }

    ~RANK()
    {
        printf("~RANK()\n");

        /*
         * Here is the problem.
         * Since my vector consists of pointers to COMBO objects,
         * I delete them upon RANK object's destruction. However,
         * std::sort() calls RANK's destructor many times and
         * throws some runtime error, unless commented out.
         */
        //for (unsigned int i = 0, n = data.size(); i < n; i++)
        //  delete data[i];
    }

    void Add(int x)
    {
        COMBO *combo = new COMBO();
        combo->x = x;

        data.push_back(combo);
    }

    unsigned int Size()
    {
        return data.size();
    }

    void Sort()
    {
        std::sort(data.begin(), data.end(), *this);
    }

    int operator[](unsigned int pos)
    {
        return data[pos]->x;
    }

    bool operator()(COMBO *combo1, COMBO *combo2)
    {
        return combo1->x > combo2->x;
    }
};

int main()
{
    RANK rank;
    rank.Add(1337);
    rank.Add(9001);
    rank.Sort();

    for (unsigned int i = 0, n = rank.Size(); i < n; i++)
        printf("%d ", rank[i]);
        printf("\n");

    system("pause");

    return 0;
}

出力 (コメント化されたデストラクタを使用):

RANK()
~RANK()
~RANK()
~RANK()
~RANK()
~RANK()
9001 1337
4

4 に答える 4

6

std::sort への比較関数は値渡しです。RANK オブジェクトをコンパレータとして使用することで、(最後の値として) にコピーを渡し、std::sort内部で複数回コピーする可能性があります。

COMBO の比較演算子をクラス RANK から分離することをお勧めします。

于 2012-11-14T18:09:52.130 に答える
2

最初の問題は、三つのルールを破っているということです。クラスは、そのリソースを解放するために重要なデストラクタを必要とするため、同じリソースを所有する複数のオブジェクトを回避するために、正しくコピー可能またはコピー不可能である必要があります。最も簡単な解決策は、コピーコンストラクターとコピー代入演算子を削除してコピーを防ぐことです。

RANK(RANK const &) = delete;
void operator=(RANK const &) = delete;

または、2011年より前のコンパイラで立ち往生している場合は、実装なしでプライベートとして宣言します。

std::unique_ptrまたは、 (コピーを防ぐため)やstd::shared_ptr(共有所有権を許可するため)などのスマートポインターを格納することを検討することもできます。これを行うと、クラスは選択したポインターと同じ(安全な)コピーセマンティクスを持ちます。

コピーを防ぐと、2番目の問題が明らかになります。RANKオブジェクトをのコンパレータとして使用していますstd::sort。コンパレータは値によって取得されるため、オブジェクトはそこにコピーされます。これは、コンパレータに別のタイプを定義することで簡単に修正できます。

struct CompareCOMBO {
    bool operator()(COMBO *combo1, COMBO *combo2) {
       return combol1->x > combo2->x;
    }
};

std::sort(data.begin(), data.end(), CompareCOMBO());

または、ラムダを使用できる場合:

std::sort(data.begin(), data.end(), 
    [](COMBO *combo1, COMBO *combo2){
         return combo1->x > combo2->x;
    }
);
于 2012-11-14T18:23:33.567 に答える
1

コピー コンストラクターを提供し、内部にブレークポイントを配置して、それが呼び出される場所を確認します。

于 2012-11-14T18:07:07.743 に答える
0

*this を比較オブジェクトとして渡すと、並べ替え中にコピーされます (コピー コンストラクターがある場合は、その呼び出しが表示されるため、構造のポップは表示されません)。

オブジェクトをソートするには、このスレッドを検討してください

于 2012-11-14T18:14:43.287 に答える