简体   繁体   English

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

[英]C++ std::sort does not work with pointer to vector

After much searching, it seems that a pointer to a vector is not the best thing to do. 经过大量搜索之后,看来指向向量的指针并不是最好的选择。 However, the following code bugs me too much: 但是,以下代码使我感到烦恼:

  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 };

with gcc 4.3 on Linux, the executable gives "double free or corruption". 在Linux上使用gcc 4.3时,可执行文件给出“双重释放或损坏”。 So I commented out line 24, and it throws 'std::out_of_range'. 所以我注释掉了第24行,并抛出了“ std :: out_of_range”。 Apparently, line 35 (sort) messes everything up when a dynamically allocated vector is passed to std::sort. 显然,将动态分配的矢量传递给std :: sort时,第35行(排序)使所有内容混乱。 Or I just had a big blunder somewhere. 或者我只是在某个地方犯了大错。 Please help!! 请帮忙!! If I change line 9 to std::vector order then things seem fine; 如果我将第9行更改为std :: vector顺序,那么一切似乎都很好; however I can't keep wondering what went wrong with the pointer to vector. 但是我不禁怀疑向量指针出了什么问题。

You are not following the Rule of Three : you haven't defined a copy constructor and copy assignment operator for your class. 您没有遵循“三规则” :您尚未为类定义复制构造函数和复制赋值运算符。

You make a copy of mhdr when you pass it as the functor to std::sort . 当您将mhdr作为函子传递给std::sort时,您将复制它。 The order data member of that copy and of the original mhdr both point to the same object. 该副本和原始mhdrorder数据成员都指向同一对象。 The copy is destroyed, causing the object pointed to by its order to be deleted, then the original is destroyed when main ends, causing a double deletion, undefined behavior, and other fun things to happen. 副本被破坏,导致按其order指向的对象被删除,然后原始副本在main结束时被破坏,从而导致重复删除,未定义行为和其他有趣的事情发生。

(In fact, even more copies might be made inside of std::sort , so it might crash even earlier.) (实际上,甚至可以在std::sort更多副本,因此它甚至可能更早崩溃。)

Why are you dynamically allocating the std::vector ? 为什么要动态分配std::vector If there are any good reasons to do that, there are very few of them. 如果有足够的理由这样做,那么其中的理由就很少了。

You're passing mhdr by value to std::sort() , with a default copy constructor that duplicates the pointer to your vector, and delete s it when that instance goes out of scope. 您正在通过值将mhdr传递给std::sort() ,并带有一个默认的复制构造函数,该构造函数复制指向您的向量的指针,并在该实例超出范围时将其delete That's not what you want. 那不是你想要的。

You should probably use a comparator object distinct from the thing holding that vector, or reference count the pointer to the vector (using an appropriate smart pointer class, probably). 您可能应该使用一个与持有该向量的对象不同的比较器对象,或者对指向该向量的指针进行引用计数(可能使用适当的智能指针类)。

You don't need bool operator()() on that class - the long s can be sorted with default comparison (see std::sort ). 您无需在该类上使用bool operator()() - long可以使用默认比较进行排序(请参阅std::sort )。 The runtime-reported problem is that the third argument is copied , and you don't have a copy constructor, nor copy assignment operator in Hdr (see rule of three ). 运行时报告的问题是第三个参数被复制了 ,并且您在Hdr没有复制构造函数,也没有复制赋值运算符(请参阅3的规则 )。

The problem is that std::sort takes the comparison functor by value, so the destructor will be invoked for the copy and for the original mhdr object, and thus, since you havent supplied a copy constructor, order will be deleted twice. 问题是std :: sort按值接受比较函子,因此将为副本和原始mhdr对象调用析构函数,因此,由于您没有提供副本构造函数,因此order将被删除两次。

The easiest fix would be to use a normal std::vector instead of a pointer to a std::vector . 最简单的解决方法是使用普通的std::vector而不是指向std::vector的指针。 By doing this the implicit copy constructor will work for you. 这样,隐式副本构造函数将为您工作。

Beside that you could define your copy constructor and make a deep copy of the order vector, or use a smart pointer to wrap it. 除此之外,您可以定义副本构造函数并制作order向量的深层副本,或者使用智能指针包装它。

But the best solution would be to make the compare function a static member function (or a global function) and using that as parameter for std::sort . 但是最好的解决方案是使compare函数成为静态成员函数(或全局函数),并将其用作std::sort参数。 You should always use dedicated functor classes. 您应该始终使用专用的仿函数类。 DONT just add an operator() to a class which already does something else. 不要将一个operator()添加到一个已经在做其他事情的类中。 It might work as expected, but most certainly it wont be as effective as a dedicated functor class, because much more copy-operations might be needed (for member variables, like in this case). 它可能会按预期工作,但最肯定的是它不会像专用函子类一样有效,因为可能需要更多的复制操作(对于这种情况下的成员变量)。 Of course you still should fix the copy-constructor of the Hdr class (or just declare a copy-ctor without definition, to remove the implicit one, which fails in this case). 当然,您仍然应该修复Hdr类的copy-constructor(或只声明一个没有定义的copy-ctor,以删除隐式的copy-ctor,在这种情况下,它将失败)。

As others mentioned, the main cause of it is that when you pass mhdr as the comparator, you are making a copy. 正如其他人提到的,主要原因是当您将mhdr用作比较器时,您正在复制。 This copy contains a pointer to the same vector. 该副本包含一个指向相同向量的指针。 When that copy gets destroyed, that vector gets destroyed, corrupting the collection that was between your iterators. 当该副本被销毁时,该向量也将销毁,从而破坏了迭代器之间的集合。

This would have been apparent if you prevented copying and assignment by declaring those operators private and not implementing then. 如果您通过声明那些运算符为私有并随后不执行这些操作来阻止复制和分配,这将是显而易见的。

The reason you got into this mess is that your Hdr class has two distinct functions -- maintaining the vector, and having the comparator function. 陷入困境的原因是您的Hdr类具有两个不同的功能-维护向量和具有比较器功能。 Classes should do one thing, and one thing well. 班级应该做一件事,而做好一件事。

The solution below fixes these problems, as well as some other problems like exposing data members as public (though I preserved the pointer to the vector since I suspect you were trying to illustrate something about that case even though I agree with the other answerers that this is a questionable decision) 下面的解决方案解决了这些问题,以及一些其他问题,例如将数据成员publicpublic (尽管我保留了指向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));
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM