C ++ std :: sort()调用析构函数

时间:2012-11-14 18:04:03

标签: c++

我重载了我的类'()运算符,将其用作排序比较器函数。当使用 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 个答案:

答案 0 :(得分:6)

std :: sort的比较函数按值传递。通过使用RANK对象作为比较器,您将副本传递给std::sort(作为最后一个值),并且可以在内部多次复制它。

我建议从类RANK

中分离出COMBO的比较运算符

答案 1 :(得分:2)

第一个问题是你打破了Rule of Three。您的类需要一个非平凡的析构函数来释放其资源,因此它需要是可正确复制的或不可复制的,以避免多个对象拥有相同的资源。最简单的解决方案是通过删除复制构造函数和复制赋值运算符来防止复制:

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());

或者,如果你可以使用lambdas:

std::sort(data.begin(), data.end(), 
    [](COMBO *combo1, COMBO *combo2){
         return combo1->x > combo2->x;
    }
);

答案 2 :(得分:1)

提供一个复制构造函数并在其中放置一个断点以查看它的调用位置。

答案 3 :(得分:0)

通过将* this作为比较对象传递,它会在排序期间被复制(这就是为什么你没有看到构造弹出的原因,如果你有一个复制构造函数,你会看到对它的调用)。

考虑this thread对对象进行排序