C ++ std :: sort不适用于指向vector的指针

时间:2011-01-10 18:28:53

标签: c++ sorting vector

经过多次搜索,似乎指向矢量的指针不是最好的选择。但是,以下代码对我来说太过分了:

  1 #include <stdio.h>
  2 #include <algorithm>
  3 #include <vector>
  4
  5
  6 class Hdr
  7 {
  8     public:
  9     std::vector<long> *order;
 10     bool operator()(long i1, long i2) const;
 11     Hdr(int N);
 12     ~Hdr();
 13 };
 14
 15 Hdr::Hdr(int N)
 16 {
 17     order = new std::vector<long>(N,0);
 18     for(int k=0;k<N;k++) (*order)[k] = -k;
 19 };
 20
 21 Hdr::~Hdr()
 22 {
 23     order->clear();
 24     delete order;
 25 };
 26
 27 bool Hdr::operator()(long i1, long i2) const
 28 {
 29     return (i1<i2);
 30 };
 31
 32 int main(void)
 33 {
 34     Hdr mhdr(1000);
 35     std::sort(mhdr.order->begin(),mhdr.order->end(),mhdr);
 36
 37     printf("value at 300 = %d\n",mhdr.order->at(300));
 38 };

在Linux上使用gcc 4.3,可执行文件提供“双重免费或损坏”。所以我注释了第24行,它抛出'std :: out_of_range'。显然,当动态分配的向量传递给std :: sort时,第35行(sort)会混淆一切。或者我在某个地方遇到了一个大错。请帮忙!!如果我将第9行更改为std :: vector order,那么事情似乎很好;但是我不禁想知道向量指针出了什么问题。

5 个答案:

答案 0 :(得分:12)

您没有关注Rule of Three:您尚未为您的班级定义复制构造函数和复制赋值运算符。

当您将mhdr作为函子传递给std::sort时,您会复制order。该副本的mhdr数据成员和原始order的{​​{1}}数据成员都指向同一个对象。副本被销毁,导致其main指向的对象被删除,然后在std::sort结束时销毁原始文件,导致双重删除,未定义的行为以及其他有趣的事情发生。 / p>

(事实上,可能会在std::vector内制作更多副本,因此它可能会更早崩溃。)

为什么要动态分配{{1}}?如果有充分的理由这样做,那就很少了。

答案 1 :(得分:5)

您将mhdr的值传递给std::sort(),默认的复制构造函数将指针复制到您的向量,并在该实例超出范围时delete。那不是你想要的。

您应该使用与持有该向量的东西不同的比较器对象,或者引用计数指向该向量的指针(可能使用适当的智能指针类)。

答案 2 :(得分:2)

您在该课程上不需要bool operator()() - 可以使用默认比较对long进行排序(请参阅std::sort)。运行时报告的问题是第三个参数是复制,并且您没有复制构造函数,也没有Hdr中的复制赋值运算符(参见rule of three)。 / p>

答案 3 :(得分:1)

问题是std :: sort按值获取比较函子,因此将为副本和原始mhdr对象调用析构函数,因此,因为您还没有提供复制构造函数,{ {1}}将被删除两次。

最简单的解决方法是使用普通order而不是指向std::vector的指针。通过这样做,隐式复制构造函数将适合您。

除此之外,您可以定义复制构造函数并制作std::vector向量的深层副本,或使用智能指针将其包装。

但最好的解决方案是使比较函数成为静态成员函数(或全局函数),并将其用作order的参数。您应该始终使用专用的函子类。不要只为已经做其他事情的类添加std::sort。它可能会按预期工作,但大多数情况下它不会像专用的functor类那样有效,因为可能需要更多的复制操作(对于成员变量,就像在这种情况下)。 当然你仍然应该修复operator()类的copy-constructor(或者只是声明一个没有定义的copy-ctor,去掉隐式的,在这种情况下会失败)。

答案 4 :(得分:0)

正如其他人提到的,它的主要原因是当你通过mhdr作为比较器时,你正在复制。此副本包含指向同一向量的指针。当该副本被破坏时,该向量将被破坏,破坏迭代器之间的集合。

如果您通过声明这些运算符是私有的而不是实现它来阻止复制和赋值,那么这将是显而易见的。

你遇到这个混乱的原因是你的Hdr类有两个不同的功能 - 保持向量,并具有比较器功能。课程应该做一件事,一件事情。

下面的解决方案修复了这些问题,以及一些其他问题,例如将数据成员公开为public(尽管我保留了指向vector的指针,因为我怀疑你试图说明这个问题即使我同意其他回答者这是一个值得怀疑的决定)

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

class Hdr
{
    public:
          Hdr(int N);
        ~Hdr();

        typedef std::vector<long>::iterator OrderIt;
        OrderIt orderBegin();
        OrderIt orderEnd();
        long orderAt(int index) const;

    private:
        Hdr& operator=(const Hdr&);
        Hdr(const Hdr&);

        std::auto_ptr<std::vector<long> > order;
};

class Comparator
{
    public:
        bool operator()(long i1, long i2) const;

};

Hdr::Hdr(int N)
{
    order = std::auto_ptr<std::vector<long> >(new std::vector<long>(N,0));
    for(int k=0;k<N;k++) 
    {
        (*order)[k] = -k;
    }
};

Hdr::~Hdr()
{
    order->clear();
};

Hdr::OrderIt Hdr::orderBegin()
{
    return order->begin();
}

Hdr::OrderIt Hdr::orderEnd()
{
    return order->end();
}

long Hdr::orderAt(int nIndex) const
{
    return order->at(nIndex);
}

bool Comparator::operator()(long i1, long i2) const
{
    return (i1<i2);
};

int main(void)
{
    Hdr mhdr(1000);
    std::sort(mhdr.orderBegin(),mhdr.orderEnd(), Comparator());
    printf("value at 300 = %d\n",mhdr.orderAt(300));
};