std :: sort过火了

时间:2011-10-28 17:43:40

标签: c++ algorithm sorting

我正在尝试使用谓词函数对对象矢量进行排序,并且我得到了一些段错误...

我有一个班级Item和一个vector< Item > _items项目列表。我需要根据显示顺序(类的数字成员)对它进行排序,我只是使用谓词函数调用一个简单的排序。

sort(_items.begin(), _items.end(), sort_item_by_display_order);

其中谓词函数是

bool sort_item_by_display_order (Item i, Item j)
{
    return i.GetDisplayOrder()>j.GetDisplayOrder();
}

和GetDisplayOrder是

int Item::GetDisplayOrder()
{
    return display_order;
}

但是......我这样做时遇到了一些段错误。然后我在谓词函数中添加了一个计数器来检查它被调用了多少次,我发现当它崩溃时,计数器大于向​​量的大小。

经过一些阅读后,我更改了代码以使用迭代器而不是使用.begin()和.end()(这不应该是相同的吗?!)

所以我现在拥有的是

vector<Item>::iterator it_start, it_end;
it_start = _items.begin();
it_end = _items.end();
sort(it_start, it_end, sort_item_by_display_order);

具有相同的谓词函数。

现在它没有崩溃,但是......对于大多数排序我做了更多的迭代然后我正在排序的矢量大小(这可能是正常的)

所以...使用_items.begin()_it_start调用排序有什么区别。据我所知,他们是一样的吗?!

还有一点需要注意。 Item是一个简单的基类,声明为

class Item
{
  private:
  (...)
  public:
  (...)
}

作为参考,我使用了http://www.cplusplus.com/reference/algorithm/sort/http://www.codeguru.com/forum/showthread.php?t=366064

在第二个链接中,他们添加了一个const和&amp;到谓词函数参数,这将使我的函数像这样

bool sort_item_by_display_order (const Item& i, const Item& j)
{
    return i.GetDisplayOrder()>j.GetDisplayOrder();
}

但是我收到编译错误:

Item.cpp|1485|error: passing `const Item' as `this' argument of `int Item::GetDisplayOrder()' discards qualifiers|

arghhh ......问题是......我做错了什么?

2 个答案:

答案 0 :(得分:4)

首先,调用比较函数的次数与集合中的元素相比更为正常。例如,当我们说排序算法的复杂度是O( n log n )时,这意味着什么。对大小 n 的集合执行的比较次数约为 n ×log( n )。 (事实上​​, n 几乎是最小次调用它;否则,我们甚至无法判断该集合是否已经在第一名。)

其次,当您将参数设置为const引用时会出现错误,因为您已将GetDisplayOrder声明为非const方法。您不允许在const对象上调用非const成员函数,因为编译器假定该方法将尝试修改该对象,即使在这种情况下它不会修改任何内容。将const添加到声明和定义的末尾:

int GetDisplayOrder() const;

int Item::GetDisplayOrder() const {
  return display_order;
}

最后,还有分段错误的问题。您在此处显示的代码不足以查明原因。你改变传递迭代器到sort的方式是正确的,这不应该有任何影响。我怀疑你的Item类需要一个复制构造函数和赋值运算符,但它们要么没有实现,要么它们没有正确实现。对矢量进行排序显然涉及在集合中移动项目,这需要一个工作分配操作符。将这些项传递给原始的比较函数,它通过值而不是const引用接受参数,需要一个工作的复制构造函数。如果您正在进行任何动态内存分配(例如使用newmalloc),则需要确保在分配或复制对象时对内存进行“深层复制”,或者你想办法让多个对象共享相同的分配。如果多个对象认为它们都拥有相同的内存块,则其中一个可能会在其他内存完成之前释放该内存,这肯定会导致分段错误(当您访问释放的内存时)。

答案 1 :(得分:0)

除了Rob Kennedy所说的,尝试在std::swap中设置断点(std::sort实际交换元素以移动它们)。如果由于某种原因无法使用调试器,您甚至可以实现自己的swap并进行一些“printf调试”。

当您点击断点时,请仔细观察是否正确复制了对象并确保没有任何损坏。这个想法是试图找到腐败的确切位置,这可能不一定会立即导致程序崩溃,但后来会导致不良影响。