yman yman - 2 months ago 16
C++ Question

Some vector elements do not change

I am experiencing very strange behaviour, which I cannot explain. I hope someone might shed some light on it.

Code snippet first:

class TContour {
typedef std::pair<int,int> TEdge; // an edge is defined by indices of vertices
typedef std::vector<TEdge> TEdges;

TEdges m_oEdges;

void splitEdge(int iEdgeIndex, int iMiddleVertexIndex) {
TEdge & oEdge = m_oEdges[iEdgeIndex];
m_oEdges.push_back(TEdge(oEdge.first, iMiddleVertexIndex));
oEdge = TEdge(oEdge.second, iMiddleVertexIndex); // !!! THE PROBLEM

void splitAllEdges(void) {
size_t iEdgesCnt = m_oEdges.size();
for (int i=0; i<iEdgesCnt; ++i) {
int iSomeVertexIndex = 10000; // some new value, not actually important
splitEdge(i, iSomeVertexIndex);

When I call
, the original edges are changed and new edges are added (resulting in doubling the container size). Everything as expected, with an exception of 1 original edge, which does not change. Should that be of any interest, its index is
and value is
. All the other original edges change, but this one remains unchanged. Adding debug prints confirms that the edge is written with a different value, but
contents does not change.

I have a simple workaround, replacing the problematic line with
m_oEdges[iEdgeIndex] = TEdge(oEdge.end, iMiddleVertexIndex);
does fix the issue. Though my concern is what is the cause for the unexpected behaviour. Might that be a compiler bug (hence what other issues do I have to expect?), or do I overlook some stupid bug in my code?

/usr/bin/c++ --version
c++ (Debian 4.9.2-10) 4.9.2

Switching from c++98 to c++11 did not change anything.


You're using an invalid reference after your push_back operation.


TEdge & oEdge = m_oEdges[iEdgeIndex];

acquires the reference. Then this:

m_oEdges.push_back(TEdge(oEdge.start, iMiddleVertexIndex));

potentially resizes the vector, and in so doing, invalidates the oEdge reference. At which point this:

oEdge = TEdge(oEdge.end, iMiddleVertexIndex);

is no longer define behavior, as you're using a dangling reference. Reuse the index, not the reference, such as:

m_oEdges[iEdgeIndex] = TEdge(m_oEdges[iEdgeIndex].end, iMiddleVertexIndex);