c++ garbage values in vector of pointer

南笙酒味 提交于 2019-11-29 16:23:21

Read the documentation of std::vector::push_back

First the description:

Adds a new element at the end of the vector, after its current last element. The content of val is copied (or moved) to the new element.

This effectively increases the container size by one, which causes an automatic reallocation of the allocated storage space if -and only if- the new vector size surpasses the current vector capacity.

Then about validity of iterators:

If a reallocation happens, all iterators, pointers and references related to the container are invalidated.

So, when you add an object to the vector, all the pointers pointing to objects in that vector may become invalid - unless you've guaranteed that the vector has enough capacity with std::vector::reserve.

Invalid means that the pointer no longer points to a valid object and dereferencing it will have undefined behaviour.

In the latter code, you never add objects to the pointed-to vector after you've stored the pointers, so the pointers are valid.

When you use push_back to add an element to a vector, it is copied into the vector. The means that, in the first example, vectorA contains a copy of objectA, and objectA goes out of scope and gets deleted right after the closing brace. This means that the pointer in pvectorA is pointing at at an address that doesn't necessarily contain objectA any more.

Your second example shouldn't work, because objectA has gone out of scope after the first loop, so I can't help you there.

When you push elements into vectorA it will occasionally get full, and have to relocate its objects to a larger memory block. That will change the address of each element.

If pvectorA has stored pointers to the elements' original position, those pointers will still point to the old positions even after the vectorA elements have been moved to a new location.

When you do vectorA.push_back you may cause that vector to reallocate itself to increase capacity, which means all its contents are moved, which means any pointers to its contents that you have saved are made invalid.

Maybe you want to rethink the whole idea of storing pointers to elements of a vector.

If you can't drop the whole idea of storing pointers, but you know the required size in advance, you could use reserve before the loop:

vectorA.reserve(size);
for(i=0; i<size; i++){
    //create objectA here
    vectorA.push_back(objectA);
    pvectorA.push_back(&vectorA[i]);
}

In this version, the pointers are valid until you either grow vectorA further or destroy it.

This is because the vector reallocated its internal storage when it grows beyond its current capacity; after the reallocation, the address of elements may have changed.

You can avoid reallocation by reserving a big enough storage beforehand:

vectorA.reserve(size);
//vectorB.reserve(size); // this would not hurt either
for(i=0; i<size; i++){
  //create objectA here
  vectorA.push_back(objectA);
  pvectorA.push_back(&vectorA[i]);
}

One final note: if you can use C++11, emplace_back constructs your object in place, hence, without copying.

If you want a sequence container with constant-time insertion and no invalidation of iterators pointing to other elements, use a std::list. Note however that std::vector is often the fastest data structure to use (in some cases, you need a pre-sorted std::vector). One prominent reason for this is that arrays are more cache friendly than e.g. trees or linked lists.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!