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(允许共享所有权);如果您这样做,那么您的类将具有与您选择的指针相同的(安全)复制语义。

防止复制将使第二个问题变得明显:您将RANK对象用作std::sort. 比较器按值取值,因此对象被复制到那里。这很容易通过为比较器定义一个单独的类型来解决:

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

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

或者,如果您可以使用 lambda:

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 回答