std::sort引发的core

本文探讨了一段C++代码中使用STL进行排序时出现的段错误问题,并深入分析了错误原因,指出在比较函数中应正确处理相等的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    1. #include <stdio.h>
    2. #include <vector>
    3. #include <algorithm>
    4. #include <new>
    5. struct foo_t
    6. {
    7.     int size;
    8. };
    9. class cmp_t
    10. {
    11. public:
    12.     bool operator()(foo_t *a, foo_t *b)
    13.     {
    14.         return a->size >= b->size;
    15.     }
    16. };
    17. int main(int argc, char *argv[])
    18. {
    19.     std::vector<foo_t *> vec;
    20.     for (int i = 0; i < 17; i++)
    21.     {
    22.         foo_t *x = new(std::nothrow) foo_t();
    23.         if (NULL == x)
    24.         {
    25.             goto fail;
    26.         }
    27.         else
    28.         {
    29.             x->size = 1;
    30.         }
    31.         vec.push_back(x);
    32.     }
    33.     std::sort(vec.begin(), vec.end(), cmp_t());
    34. fail:
    35.     for(std::vector<foo_t *>::iterator iter = vec.begin(); vec.end() != iter; ++iter)
    36.     {
    37.         delete *iter;
    38.         *iter = NULL;
    39.     }
    40.     return 0;
    41. }
    42. 然后编译
      1. g++ main.cpp -Werror -Wall -g
      然后执行,此时系统出core,错误类型为段错误
      如果无core文件产生,可以使用
      1. ulimit -c unlimited
      后重新执行一次,此时就会有core文件生成
      然后
      1. gdb a.out core
      2. (gdb) bt
      3. #0  0x0804889e in cmp_t::operator() (this=0xbfed92d0, a=0x0, b=0x9a9d0c8) at main.cpp:16
        #1  0x080497ff in std::__unguarded_partition<__gnu_cxx::__normal_iterator<foo_t**, std::vector<foo_t*, std::allocator<foo_t*> > >, foo_t*, cmp_t> (__first=..., __last=..., __pivot=@0x9a9d1a0, __comp=...) at /usr/include/c++/4.6/bits/stl_algo.h:2233
        #2  0x0804926a in std::__unguarded_partition_pivot<__gnu_cxx::__normal_iterator<foo_t**, std::vector<foo_t*, std::allocator<foo_t*> > >, cmp_t> (__first=..., __last=..., __comp=...) at /usr/include/c++/4.6/bits/stl_algo.h:2265
        #3  0x08048e84 in std::__introsort_loop<__gnu_cxx::__normal_iterator<foo_t**, std::vector<foo_t*, std::allocator<foo_t*> > >, int, cmp_t> (
            __first=..., __last=..., __depth_limit=7, __comp=...) at /usr/include/c++/4.6/bits/stl_algo.h:2306
        #4  0x08048a22 in std::sort<__gnu_cxx::__normal_iterator<foo_t**, std::vector<foo_t*, std::allocator<foo_t*> > >, cmp_t> (__first=...,
            __last=..., __comp=...) at /usr/include/c++/4.6/bits/stl_algo.h:5368
        #5  0x080487ce in main (argc=1, argv=0xbfed9464) at main.cpp:38

      可以看到,系统core在了排序函数里面。
      然后通过分析stl代码发现以下一段代码
      1. /// This is a helper function...
      2.   template<typename _RandomAccessIterator, typename _Tp, typename _Compare>
      3.     _RandomAccessIterator
      4.     __unguarded_partition(_RandomAccessIterator __first,
      5.              _RandomAccessIterator __last,
      6.              const _Tp& __pivot, _Compare __comp)
      7.     {
      8.       while (true)
      9.     {
      10.      while (__comp(*__first, __pivot))
      11.      ++__first;
      12.      --__last;
      13.      while (__comp(__pivot, *__last))
      14.      --__last;
      15.      if (!(__first < __last))
      16.      return __first;
      17.      std::iter_swap(__first, __last);
      18.      ++__first;
      19.     }
      20.     }
      此函数完成快速排序中分区功能,即将比哨兵小的数据放在其前,大的放在其后。
      函数中使用的是
      while (__comp(*__first, __pivot))
          ++__first;

      如果当比较元素相同返回真时,此时比较元素将会继续向下遍历,在极端情况下,例如程序中所有元素都是一样的情况下,在这种情况下,就会出现访问越界,结果就是导致程序出现segment fault

      所以在写c++ stl中的比较函数是,bool返回真的时候,一定是“真的”大,或者小,等于的时候只能返回false。


namespace zkos { namespace soa { namespace servicemethod1 { ZKOS_MODULE_VERSION class ServiceProxyTest : public testing::Test { public: void SetUp() override { app_id_ = "1"; app_name_ = "tcp_client";//客户端 app_token_= "test_domain"; instance_name_ = "1"; zaid_ = ""; MockServiceFramework mockServiceFramework; MockServiceProxy MockServiceProxydata; mockServiceFrameworkPtr_ = std::make_shared<MockServiceFramework>(); mockServiceProxyPtr_ = std::make_shared<MockServiceProxy>(); EXPECT_CALL(*mockServiceFrameworkPtr_, CreateServiceProxy(_)).WillRepeatedly(Return(std::shared_ptr<ServiceProxy>(mockServiceProxyPtr_))); EXPECT_CALL(*mockServiceProxyPtr_, MethodCallSync(_, _)).WillRepeatedly(testing::Invoke([]() -> zkos::core::Result<Response>{ return zkos::core::Error((int)ErrorCode::kTimeout)<< "MethodCallSync is failed|timeout triggered in service"; })); EXPECT_CALL(*mockServiceProxyPtr_, RegisterServiceState(_)) .WillRepeatedly(testing::Invoke([](const std::function<void(zkos::service::ServiceState)>& handler) { if (handler) { handler(zkos::service::ServiceState::kAvailable); } })); EXPECT_CALL(*mockServiceProxyPtr_, RegisterSubscriptionState(_)) .WillRepeatedly(testing::Invoke([](const std::function<void(const std::string&, zkos::service::SubscriptionState)>& handler) { if (handler) { std::string topic = "test_topic"; handler(topic, zkos::service::SubscriptionState::kSubscribed); } })); EXPECT_CALL(*mockServiceProxyPtr_, RegisterDeserializer(_,_)).WillRepeatedly(testing::Invoke([]() -> zkos::core::Result<void>{ return {}; })); EXPECT_CALL(*mockServiceProxyPtr_, UnSubscribe(_)).WillRepeatedly(testing::Invoke([]() -> zkos::core::Result<void>{ return {}; }));
最新发布
03-26
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值