Problem storing tvmet vector objects in an stl vector container

Discussion in 'C++' started by alexjcollins@gmail.com, Sep 8, 2008.

1. Guest

The following program demonstrates the problem:

#include <vector>
#include <iostream>
#include <tvmet/Vector.h>

typedef tvmet::Vector<double, 3> Vector3d;

class Mesh
{
public:
private:
std::vector<Vector3d> m_tVertices;
};

{ m_tVertices.push_back(tVertex);
return &m_tVertices.back();
}

int main()
{
Mesh tMesh;
Vector3d* pVertex0 = tMesh.addVertex(Vector3d(-1, 1, 1));
std::cout << "Vertex0: " << (*pVertex0)(0) << ", " << (*pVertex0)
(1) << ", " << (*pVertex0)(2) << std::endl;
Vector3d* pVertex1 = tMesh.addVertex(Vector3d( 1, 1, 1));
std::cout << "Vertex0: " << (*pVertex0)(0) << ", " << (*pVertex0)
(1) << ", " << (*pVertex0)(2) << std::endl;
std::cout << "Vertex1: " << (*pVertex1)(0) << ", " << (*pVertex1)
(1) << ", " << (*pVertex1)(2) << std::endl;
return 0;
}

Which gives the following output:

Vertex0: -1, 1, 1
Vertex0: 0, 1, 1
Vertex1: 1, 1, 1

Vertex0: -1, 1, 1
Vertex0: -1, 1, 1
Vertex1: 1, 1, 1

It is interesting to note that the code behaves correctly if an stl
list is used instead. I can't work out why this is not working, and it
seems like such a trivial program! Could anyone explain to me what is
wrong?

, Sep 8, 2008

2. Guest

On Sep 8, 9:17 pm, Victor Bazarov <> wrote:
> wrote:
> > The following program demonstrates the problem:

>
> > #include <vector>
> > #include <iostream>
> > #include <tvmet/Vector.h>

>
> > typedef tvmet::Vector<double, 3> Vector3d;

>
> > class Mesh
> > {
> > public:
> >     Vector3d* addVertex(const Vector3d& tVertex);
> > private:
> >     std::vector<Vector3d> m_tVertices;
> > };

>
> > Vector3d* Mesh::addVertex(const Vector3d& tVertex)
> > {   m_tVertices.push_back(tVertex);
> >     return &m_tVertices.back();
> > }

>
> > int main()
> > {
> >     Mesh tMesh;
> >     Vector3d* pVertex0 = tMesh.addVertex(Vector3d(-1, 1, 1));
> >     std::cout << "Vertex0: " << (*pVertex0)(0) << ", " << (*pVertex0)
> > (1) << ", " << (*pVertex0)(2) << std::endl;
> >     Vector3d* pVertex1 = tMesh.addVertex(Vector3d( 1, 1, 1));
> >     std::cout << "Vertex0: " << (*pVertex0)(0) << ", " << (*pVertex0)
> > (1) << ", " << (*pVertex0)(2) << std::endl;
> >     std::cout << "Vertex1: " << (*pVertex1)(0) << ", " << (*pVertex1)
> > (1) << ", " << (*pVertex1)(2) << std::endl;
> >     return 0;
> > }

>
> > Which gives the following output:

>
> > Vertex0: -1, 1, 1
> > Vertex0: 0, 1, 1
> > Vertex1: 1, 1, 1

>
> > Instead of the expected output:

>
> > Vertex0: -1, 1, 1
> > Vertex0: -1, 1, 1
> > Vertex1: 1, 1, 1

>
> > It is interesting to note that the code behaves correctly if an stl
> > list is used instead. I can't work out why this is not working, and it
> > seems like such a trivial program! Could anyone explain to me what is
> > wrong?

>
> 'push_back' *is allowed* to invalidate all pointers and iterators to any
> of the vector's elements.  So, storing 'pVertex0' is probably a bad idea
> if you intend to grow the vector (matrix).
>
> V
> --

Thanks, that makes sense.
Is push_back allowed to invalidate pointers when using a list?

, Sep 8, 2008

3. Juha NieminenGuest

wrote:
> Is push_back allowed to invalidate pointers when using a list?

AFAIK std::list is guaranteed to preserve pointers to existing
elements valid even if new elements are added.

If you need random access (and more efficient memory usage) you might
want to consider using std::deque instead of std::vector. The former
behaves mostly like std::vector, but pointers are not invalidated.

Juha Nieminen, Sep 8, 2008