sro5h
sro5h

Reputation: 322

If I push the pointer of an element allocated on the stack into an std::vector its member's values get altered

If I add more than 2 items to the std::vector<A*> in the way shown below, the member's values of the added items change
Here is a Minimal, Complete and Verifiable Example:

#include <iostream>
#include <vector>

struct B;

struct C
{
    float x;

    C(float x)
    {
        this->x = x;
    }
};

struct A : public C
{
    bool begin;
    bool visible;
    B* b;

    A(float x, B* parent)
       : C(x)
    {
        begin = false;
        visible = false;
        b = parent;
    }
};

struct B
{
    A a1;
    A a2;

    B(float x1, float x2)
         : a1(x1, this), a2(x2, this)
    {
        a1.visible = true;
    }
};

int main()
{
    std::vector<B> bs;
    std::vector<A*> as;
    bs.push_back(B(1, 2));
    as.push_back(&bs.back().a1);
    as.push_back(&bs.back().a2);
    bs.push_back(B(2, 3));
    as.push_back(&bs.back().a1);
    as.push_back(&bs.back().a2);

    for(auto& it : as)
    {
        std::cout << it->begin << std::endl;
    }

    std::cin.get();

    return EXIT_SUCCESS;
}

There's another Problem with the above code(it already got mentioned in the comments by tobi303): The pointer B* b from struct A becomes invalid due to push_back(B(...)) copying the instance of B, the solution is to use emplace_back instead

Upvotes: 1

Views: 64

Answers (1)

Maxim Egorushkin
Maxim Egorushkin

Reputation: 136405

The problem is that when more elements are added to a vector it may resize itself. When this happens all elements are moved to a new location and all existing pointers and references to elements get invalidated.

There are containers that do not invalidate iterators when new elements are added, such as std::list and boost::stable_vector.

I.e. boost::stable_vector<Segment> or std::list<Segment> instead of std::stable<Segment> would fix the issue, provided you do not require contiguous storage of Segment elements.

Upvotes: 4

Related Questions