C++ 记一次debug core dump

背景是想多线程并行处理数据。但是出现了core。代码简化如下:

struct Result {
    Ads& a;
    Ads& b;
    std::string s;
};

    static TaskManager task_manager(3);   //线程池
    std::vector<std::function<int()>> task_list;
    task_list.reserve(3);
    std::vector<Result> rets;
    for (size_t i = 0; i < 3; i++) {   //并行的三个任务
        rets.push_back(std::move(Result{t_ins[i], t_exs[i], ""}));
        LOG("before search ret %p %p %d", &rets[i], &rets[i].a, rets[i].a.num());
        
        task_list.push_back(std::bind(&Index::between, this,
                std::cref(ctx), std::ref(rets[i]) ));

		// 匿名函数使用有问题,rets传入后为空,待以后排查。有能之士也可以解惑一下。
        // task_list.push_back([&]()->int{
        //                         return this->between(ctx, rets[i]);
        //                     });
    }
    task_manager.run(std::move(task_list));

这份代码会有core。core的现象:
在这里插入图片描述
上图中左上为进入线程前rets的各个地址,右上为进入线程前变量rets[i].a的各个地址。
左下为进入线程后rets的各个地址,右下为进入线程后变量rets[i].a的各个地址。
可以发现,进入线程前后rets的各个地址都是正常的,但是进入线程前后rets[i].a的各个地址中只有一个是对的,其余两个的都是错的。

这个问题很隐晦,有个是正常的,但是有2个是错误的。
其原因出在push back上。在没有reserve的情况下,vector会进行自动扩容。在for 3循环情况下,每次的push back都会自动扩容,导致之前传递的引用值失效。只有最后一次push back是正常的。
解决办法:

rets.reserve(speeds);
// 扩容验证
#include <iostream>
#include <vector>
using namespace std;

struct A{
	int& b;
};

int main()
{
	int d = -1;
X
	A c{d};
	cout << c.b << " " << &c << " " << &c.b << endl;

	vector<A> e;
	e.push_back(c);
	cout << e[0].b << " " << &e[0] << " " << &e[0].b << endl;
	
	for(int i=1; i<10; i++){
		e.push_back(move(c));
		cout << e[0].b << " i" << i << " " << &e[0] << " " << &e[0].b << endl;
	}
   return 0;
}

输出:
-1 0x7ffd2394cf40 0x7ffd2394cf48
-1 0x132ae80 0x7ffd2394cf48
-1 i1 0x132aea0 0x7ffd2394cf48
-1 i2 0x132aec0 0x7ffd2394cf48
-1 i3 0x132aec0 0x7ffd2394cf48
-1 i4 0x132aef0 0x7ffd2394cf48
-1 i5 0x132aef0 0x7ffd2394cf48
-1 i6 0x132aef0 0x7ffd2394cf48
-1 i7 0x132aef0 0x7ffd2394cf48
-1 i8 0x132af40 0x7ffd2394cf48
-1 i9 0x132af40 0x7ffd2394cf48

那么问题来了?为啥rets的地址没有出现问题,而是rets[i].a出现地址问题呢?
C++ 中 vector 重新分配内存是怎样实现的?
重新分配内存后,会将原有对象析构。
那么问题又来了?为啥内存重分配后线程内部rets的地址仍然正确的呢?
猜测std::ref绑定的是重新分配后的地址。
那么问题又来了?在rets.reserve(3)后,为啥匿名函数像上述写法会仍然core呢?
猜测是i是引用的方式传递的,但循环过程中i的值变了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值