C++容器存放引用的小坑与分析

 
Category: C++

问题

最近做图论题发现一个bug, 在这里记录一下:

vector<pair<int, int>> vp{ {1, 2}, {2, 3} };
for (size_t i{}; i < 4; ++i) {
    if (i < vp.size()) {
        auto& [a, b] = vp[i];
        vp.emplace_back(a, b);
        cout << a << " : " << b << endl;
    }
}

在 address-sanitizer 直接报:

==1705==ERROR: AddressSanitizer: heap-use-after-free on address 0x0001051006f0 at pc 0x000102669330 bp 0x00016d796790 sp 0x00016d796788

问题出在哪了呢?

定位一下错误发现, 原来是引用搞的鬼, 再来看下面的精简一点的例子, 就能发现问题了:

vector<int> vp{1, 2, 3};
for (size_t i{}; i < 4; ++i) {
    if (i < vp.size()) {
        int& a = vp[i];
        cout << "before: " << a << endl; // 1
        vp.push_back(a);
        cout << "after: " << a << endl; // X: 不能访问 a 了
    }
}

在 before 输出 1 之后, 出现内存问题, 也就是说问题出现在 push_back 这里了, 构造本身是没问题的, 但是 & 这个符号是不对的(又一次被&坑了), 容器内元素的引用传入容器就会导致引用变量变成野指针!

这时候注释掉第七行, 问题就解决了, 但这也说明引用变量的一个问题, 引用的变量 通过 push_back 传入容器之后, 本身的值就会失效, 当然这只是针对容器内元素的引用来说的, 如果传入的是外部变量的引用, 则没有这个问题.