【发布时间】:2021-01-03 09:33:07
【问题描述】:
为什么 valgrind 会为这段代码返回错误?
#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==
这让我怀疑取消引用向量返回的地址是否具有未定义的行为,这是合法的代码吗?
【问题讨论】:
-
由于重新分配问题,指向元素的指针和迭代器都很容易失效,最好保存 indexes。
-
另一种可能的解决方案是在之前设置向量的大小,并且只使用索引。或者在您的情况下,可以使用
std::iota而不是显式循环来解决。 -
@Someprogrammerdude OP 并没有要求解决方法,但他们很清楚地询问显示的代码是否合法。
-
@cigien 好吧,我没有写答案,只有 cmets。
-
@cigien true,但欢迎提出任何建议。问题来了,因为“重新分配内存”的库根本没有明确这一点,例如g_array(来自 glib)使用类似的概念(使用
realloc),我认为澄清它是非常合适的,因为它可以引入错误。我看到std::vector的情况相同,但可能是在这种情况下它有据可查,标准中是否有任何参考?
标签: c++ vector dereference