发现VC自带STL库的lower_bound的bug!

chenyu2202863 2010-11-03 10:37:02
很遗憾,M$的bug导致我愤怒不已!(VC2008)

lower_bound在debug和release模式下,对同一份源码的编译会产生不同的结果。
在debug下,_DEBUG_LT_PRED宏导致对函数参数的编译错误,虽说这个宏帮助了检测运行错误,但是却改变了用户行为~

测试代码如下:


#include <algorithm>
#include <functional>

#include <iostream>

#include <list>



struct Test
{
int priority_;

Test(int prio)
: priority_(prio)
{}
};
// 排序所用
bool Less(const Test *lhs, const Test *rhs)
{
return lhs->priority_ < rhs->priority_;
}


struct FindIf
{
// 在debug、release模式下,才真正用来比较的
bool operator()(const Test *t, int prio) const
{
return prio < t->priority_;
}

// 在debug模式下,需要此重载进行迭代器检测
/*bool operator()(int prio, const Test *t) const
{
return prio < t->priority_;
}*/

// 在debug模式下,需要此重载进行迭代器检测
/*bool operator()(const Test *lhs, const Test *rhs) const
{
return lhs->priority_ < rhs->priority_;
}*/
};


int _tmain(int argc, _TCHAR* argv[])
{
std::list<Test *> queue_;
queue_.push_back(new Test(2));
queue_.push_back(new Test(1));
queue_.push_back(new Test(5));
queue_.push_back(new Test(3));
queue_.push_back(new Test(4));

std::stable_sort(queue_.begin(), queue_.end(), Less);

std::lower_bound(queue_.begin(), queue_.end(), 3, FindIf());

system("pause");
return 0;
}



有兴趣的童鞋,可以在debug与release模式下分别编译试试
...全文
329 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
x642458 2010-11-03
  • 打赏
  • 举报
回复
list容器可以这样用stable_sort(queue_.begin(), queue_.end(), Less);?
第一次听说
chenyu2202863 2010-11-03
  • 打赏
  • 举报
回复
那个宏检测对弱排序行检测是没问题的,问题出在对debug和release两种状态下的编译结果不同。
qq120848369 2010-11-03
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 abigwood 的回复:]
这样的比较规则,让我很忧郁啊

C/C++ code

struct FindIf
{
bool operator()(const Test *t, int prio) const
{
return prio < t->priority_;
}
};
[/Quote]

template<class _FwdIt,
class _Ty,
class _Diff,
class _Pr> inline
_FwdIt _Lower_bound(_FwdIt _First, _FwdIt _Last,
const _Ty& _Val, _Pr _Pred, _Diff *)
{ // find first element not before _Val, using _Pred
_Diff _Count = 0;
_Distance(_First, _Last, _Count);
for (; 0 < _Count; )
{ // divide and conquer, find half that contains answer
_Diff _Count2 = _Count / 2;
_FwdIt _Mid = _First;
_STD advance(_Mid, _Count2);

if (_Pred(*_Mid, _Val))
// if (_DEBUG_LT_PRED(_Pred, *_Mid, _Val))
{ // try top half
_First = ++_Mid;
_Count -= _Count2 + 1;
}
else
_Count = _Count2;
}
return (_First);
}
你看看_Pred怎么调用的就知道为什么这么写了.
aBigWood 2010-11-03
  • 打赏
  • 举报
回复
这样的比较规则,让我很忧郁啊

struct FindIf
{
bool operator()(const Test *t, int prio) const
{
return prio < t->priority_;
}
};

qq120848369 2010-11-03
  • 打赏
  • 举报
回复
修正:是Advance函数的作用,接受(Iter fisrt,int n)。
qq120848369 2010-11-03
  • 打赏
  • 举报
回复
再具体点就是,将traits_Iterator<Iter>::type作为模板参数生成一个_advance的类对象,template<class Iter_Type> class _advacne(bool operator()(Iter_Type first,Iter_Type end)). 给_advance特化各种迭代器就行了.

或者_advance干脆就是个函数,重载各个迭代器就行.
qq120848369 2010-11-03
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 hastings 的回复:]
2010表示毫无压力~~
发现现在的库先进了:
template <class RandomAccessIterator>
void stable_sort ( RandomAccessIterator first, RandomAccessIterator last );

template <class RandomAccessIterator, class Compare>
……
[/Quote]

是Advance函数的作用,接受(Iter fisrt,Iter end)迭代器,然后萃取迭代器的类型traits_Iterator<Iter>::type,大体就这意思,根据类型,选择while逐步迭代还是直接RandomAccessIterator类型+n直接到位.

这个早有了.
hastings 2010-11-03
  • 打赏
  • 举报
回复
2010表示毫无压力~~
发现现在的库先进了:
template <class RandomAccessIterator>
void stable_sort ( RandomAccessIterator first, RandomAccessIterator last );

template <class RandomAccessIterator, class Compare>
void stable_sort ( RandomAccessIterator first, RandomAccessIterator last,
Compare comp );
要求的是随机迭代器,list的迭代器居然也已经可以用了~~
qq120848369 2010-11-03
  • 打赏
  • 举报
回复
不得不提一点,lower_bound里的二分查找做法,这里必须要求排序不是弱排序,否则结果不堪设想,找到的极有可能不是第一个满足条件的点.
qq120848369 2010-11-03
  • 打赏
  • 举报
回复
看了一下源码,不知道是不是这里的问题,楼主自行了解,反正第一个算法是,第二个算法是二分查找.
重点关注注释部分的宏定义到底是什么.

// TEMPLATE FUNCTION _Debug_lt_pred
template<class _Pr, class _Ty1, class _Ty2> inline
bool _Debug_lt_pred(_Pr _Pred,
const _Ty1& _Left, const _Ty2& _Right,
_Dbfile_t _File, _Dbline_t _Line)
{ // test if _Pred(_Left, _Right) and _Pred is strict weak ordering
if (!_Pred(_Left, _Right))
return (false);
else if (_Pred(_Right, _Left))
_DEBUG_ERROR2("invalid operator<", _File, _Line);
return (true);
}

上边是追踪宏到最后,意思就是如果在lower_bound里发现ptr()成功,继续宏判断排序是否是一个弱排序,
即如果left==right的情况存在,那么就是一个弱排序,通过if (!_Pred(_Left, _Right))和if (_Pred(_Right, _Left))一起完成了这个判断.


以下是lower_bound的代码:

template<class _FwdIt,
class _Ty,
class _Diff,
class _Pr> inline
_FwdIt _Lower_bound(_FwdIt _First, _FwdIt _Last,
const _Ty& _Val, _Pr _Pred, _Diff *)
{ // find first element not before _Val, using _Pred
_Diff _Count = 0;
_Distance(_First, _Last, _Count);
for (; 0 < _Count; )
{ // divide and conquer, find half that contains answer
_Diff _Count2 = _Count / 2;
_FwdIt _Mid = _First;
_STD advance(_Mid, _Count2);

if (_Pred(*_Mid, _Val))
// if (_DEBUG_LT_PRED(_Pred, *_Mid, _Val))
{ // try top half
_First = ++_Mid;
_Count -= _Count2 + 1;
}
else
_Count = _Count2;
}
return (_First);
}


所以楼主发现debug和realse结果不同,很有可能就是这个宏做了一些处理,由于宏里在发现是弱排序时,会调换left,right,就是调用ptr(val,*t),而楼主原本的定义是ptr(*t,val).

其实我也不知道再具体问题是怎么回事,只是一个探索.
Jim_King_2000 2010-11-03
  • 打赏
  • 举报
回复
http://connect.microsoft.com/visualstudio/feedback

到上面的链接去报bug。
lsupper 2010-11-03
  • 打赏
  • 举报
回复
GCC欢迎你.........
qq120848369 2010-11-03
  • 打赏
  • 举报
回复
VC6呀?
gules 2010-11-03
  • 打赏
  • 举报
回复
我从不用VC,VS系列,不知道后续版本是此问题否?
zenny_chen 2010-11-03
  • 打赏
  • 举报
回复
不用VC的飘过……
不用STL的游过……
chenyu2202863 2010-11-03
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 qq120848369 的回复:]
引用 12 楼 abigwood 的回复:
这样的比较规则,让我很忧郁啊

C/C++ code

struct FindIf
{
bool operator()(const Test *t, int prio) const
{
return prio < t->priority_;
}
};


const防止修改私有成员变量,这里FindIf本身没成员变量,cons……
[/Quote]

如果作为有效性讨论,还真没意义··~
qq120848369 2010-11-03
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 abigwood 的回复:]
这样的比较规则,让我很忧郁啊

C/C++ code

struct FindIf
{
bool operator()(const Test *t, int prio) const
{
return prio < t->priority_;
}
};
[/Quote]

const防止修改私有成员变量,这里FindIf本身没成员变量,const真的没意义。

64,646

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧