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 扩展向量时,索引数组将在内存中移动,因此在第一次实现具体实现后,您对它们的任何指针都将变得无效。
为什么 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 扩展向量时,索引数组将在内存中移动,因此在第一次实现具体实现后,您对它们的任何指针都将变得无效。