Valgrind 取消引用 std::vector 返回的地址时出错

Valgrind error dereferencing an address returned by std::vector

为什么 valgrind returns 这段代码出错?

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> vec;
    int *ptr;

    for (int i = 0; i < 1000; i++)
    {
        vec.push_back(i);
        if (i == 100)
        {
            ptr = &vec[i];
        }
    }
    std::cout << ptr << "\n";  // Print address of -> Ok
    std::cout << *ptr << "\n"; // Print content of -> Ok but with a valgrind error
}

编译:g++ -Wall -Wpedantic -O0 -o demo demo.cpp

valgrind 错误是:

==3982== Invalid read of size 4
==3982==    at 0x1093A7: main (in /home/david/demo)
==3982==  Address 0x4dae1e0 is 400 bytes inside a block of size 512 free'd
==3982==    at 0x483E1CF: operator delete(void*, unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==3982==    by 0x109EB4: __gnu_cxx::new_allocator<int>::deallocate(int*, unsigned long) (in /home/david/demo)
==3982==    by 0x109B5B: std::allocator_traits<std::allocator<int> >::deallocate(std::allocator<int>&, int*, unsigned long) (in /home/david/demo)
==3982==    by 0x10970F: std::_Vector_base<int, std::allocator<int> >::_M_deallocate(int*, unsigned long) (in /home/david/demo)
==3982==    by 0x109A3B: void std::vector<int, std::allocator<int> >::_M_realloc_insert<int const&>(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, int const&) (in /home/david/demo)
==3982==    by 0x10964F: std::vector<int, std::allocator<int> >::push_back(int const&) (in /home/david/demo)
==3982==    by 0x109354: main (in /home/david/demo)
==3982==  Block was alloc'd at
==3982==    at 0x483CE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==3982==    by 0x10A0FF: __gnu_cxx::new_allocator<int>::allocate(unsigned long, void const*) (in /home/david/demo)
==3982==    by 0x109F73: std::allocator_traits<std::allocator<int> >::allocate(std::allocator<int>&, unsigned long) (in /home/david/demo)
==3982==    by 0x109DAD: std::_Vector_base<int, std::allocator<int> >::_M_allocate(unsigned long) (in /home/david/demo)
==3982==    by 0x1098BC: void std::vector<int, std::allocator<int> >::_M_realloc_insert<int const&>(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, int const&) (in /home/david/demo)
==3982==    by 0x10964F: std::vector<int, std::allocator<int> >::push_back(int const&) (in /home/david/demo)
==3982==    by 0x109354: main (in /home/david/demo)
==3982== 

这让我怀疑取消引用向量返回的地址是否有未定义的行为,这是合法的代码吗?

Valgrind 说这是一次“无效读取”。在 push_back 操作期间,std::vector 将根据需要重新分配内存并将所有数据复制到新位置。

如果是这样,您的 ptr 可能指向不再分配给向量 vec 的内存。

所以是的,它可能是您使用它的方式。

如果您已经知道要插入的元素个数,最好先reserve内存,然后简单地将元素插入到正确的位置。

关于解引用向量索引指针问题的最后一部分。

如果我错了请纠正我,但我的理解是矢量中的元素只是指向实际数据的指针。向量元素数组必须在连续的内存中,以便可以对它们进行索引,但数据可以在任何地方。

扩展向量很快,因为您只需将索引移动到新的更大的连续内存块,而不是实际数据。第一次使用 .push_back 扩展向量时,索引数组将在内存中移动,因此在第一次实现具体实现后,您对它们的任何指针都将变得无效。