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

C++ 取消引用std::vector返回的地址时出错,c++,vector,dereference,C++,Vector,Dereference,为什么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

为什么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
}

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

Valgrind说这是无效读取。在push_-back操作期间,如果需要,std::vector将重新分配内存,并将所有数据复制到新位置

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

所以是的,这可能是你使用它的方式


如果您已经知道要插入的元素数量,最好先保留内存,然后只需将元素插入正确的位置。

Valgrind说这是无效读取。在push_-back操作期间,如果需要,std::vector将重新分配内存,并将所有数据复制到新位置

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

所以是的,这可能是你使用它的方式


如果您已经知道要插入的元素数量,最好先保留内存,然后只需在正确的位置插入元素。

关于问题的最后一部分,即取消对向量索引的引用

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


扩展向量很快,因为您只需将索引移动到一个新的更大的连续内存块,而不必移动实际数据。第一次使用展开向量时。推回索引数组将在内存中移动,因此在第一次使用特定于实现的指针后,指向它们的任何指针都将无效。

关于问题的最后一部分,即取消指向向量索引的指针的引用

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


扩展向量很快,因为您只需将索引移动到一个新的更大的连续内存块,而不必移动实际数据。第一次使用展开向量时。推回索引数组将在内存中移动,因此在第一次使用特定于实现的指针后,所有指向它们的指针都将失效。

由于重新分配问题,指向元素的指针和迭代器都很容易失效,另一个可能的解决方案是在之前设置向量的大小,只使用索引。或者在您的情况下,它可以用而不是显式循环来解决。@Someprogrammerdude OP没有要求解决方法,但他们很清楚地问显示的代码是否合法。@cigien好吧,我不是在写答案,只写注释。@cigien true,但欢迎任何建议。这个问题的出现是因为重新分配内存的库根本就不清楚这一点,例如from glib使用了一个类似的概念,使用realloc,我认为澄清它是非常合适的,因为它可能会引入bug。我发现std::vector的情况也一样,但在这种情况下,它可能有很好的文档记录,标准中是否有任何引用?由于重新分配问题,指向元素的指针和迭代器都很容易失效,另一个可能的解决方案是在之前设置向量的大小,只使用索引。或者在您的情况下,它可以用而不是显式循环来解决。@Someprogrammerdude OP没有要求解决方法,但他们很清楚地问显示的代码是否合法。@cigien好吧,我不是在写答案,只写注释。@cigien true,但欢迎任何建议。这个问题的出现是因为重新分配内存的库根本就不清楚这一点,例如from glib使用了一个类似的概念,使用realloc,我认为澄清它是非常合适的,因为它可能会引入bug。我看到std::vector的情况也一样,但可能是在这种情况下,它有很好的文档记录,标准中有任何参考吗?实际上,我认为它可能只是UB。一个实现可能已经分配了足够的内存,这样在获取元素地址后就不会进行重新分配了。@cigien:是的,你是对的。我将更新另一种方法是不获取一个元素的地址以供将来使用,而是获取其在向量中的索引,用于编辑答案以澄清关于UB的位。我做了一些小的修改来清理一下答案,希望没问题。事实上,我认为可能只是UB。实现可以分配足够的内存,以便
o重新分配是在获取元素地址后进行的。@cigien:是的,你是对的。我将更新另一种方法是不获取一个元素的地址以供将来使用,而是获取其在向量中的索引,用于编辑答案以澄清关于UB的位。我已经做了一些小的编辑来稍微整理一下答案,希望没问题。向量中的元素只是指向实际数据的指针。你能详细说明一下吗?据我所知,向量是指向连续内存区域的指针,类似于可扩展数组。。。数据可以在任何地方。。。如果你的意思是它们是一个指针数组,其中每个元素都在零碎的内存中,那么我认为你错了。如果你取消引用一个向量的名称,它将给出指向你的数据的指针数组中第一个元素的当前地址。我认为向量的一个主要特征是,你的数据类型有多大并不重要,因为当你展开一个向量时,只有指向数据的指针会移动得很快。C++风格的字符串与向量非常相似,但是在一个字符中存储指针是愚蠢的,所以数据实际上存储在索引中。我不同意向量不存储指针,但是谢谢C++的回答。啊,我不是指C/C++风格指针。向量的索引是指向数据元素的句柄或向量,但它们仍然指向数据,它们不是实际数据。向量中的元素只是指向实际数据的指针。你能详细说明一下吗?据我所知,向量是指向连续内存区域的指针,类似于可扩展数组。。。数据可以在任何地方。。。如果你的意思是它们是一个指针数组,其中每个元素都在零碎的内存中,那么我认为你错了。如果你取消引用一个向量的名称,它将给出指向你的数据的指针数组中第一个元素的当前地址。我认为向量的一个主要特征是,你的数据类型有多大并不重要,因为当你展开一个向量时,只有指向数据的指针会移动得很快。C++风格的字符串与向量非常相似,但是在一个字符中存储指针是愚蠢的,所以数据实际上存储在索引中。我不同意向量不存储指针,但是谢谢C++的回答。啊,我不是指C/C++风格指针。向量的索引是指向数据元素的句柄或向量,但它们仍然指向数据,而不是实际数据。
==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==