I thought I knew how to use vector and manage insert, push_back and erase, but apparently I don't. I encounter an unexpected outcome when i attempt to erase the second element in a vector of four: the element is removed, yet the content of the element following it is modified. I'm missing something obvious, I guess. Here's a trimmed down version of the code:

del.h:

#ifndef _DEL_H
#define _DEL_H

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
#include <locale>
#include <cmath>
#include <math.h>
#include <float.h>
#include <string>
#include <sstream>
#include <cstdlib>

class CZo
{
	protected:
		std::vector<int> vEx;
		int l;
	public:
		CZo();
		CZo(
			const CZo & Z );
		CZo & operator = (
			const CZo & Z );
		void setL(
			int i );
		void addEx(
			int iEx );
		int iL() const;
		int iNumberEx() const;
		bool bEx(
			int iEx ) const;
};

class CBl
{
	protected:
		std::vector<CZo> vZo;
	public:
		void setL(
			int iZo,
			int iL );
		void addEx(
			int iZo,
			int iEx );
		int iL(
			int iZo ) const;
		bool bEx(	
			int iZo,
			int iEx ) const;
		int iNumberZo() const;
		void addZo();
		void insertZo(
			int iZo );
		std::vector<CZo>::iterator deleteZo(
			int iZo );
};

#endif

del.cpp:

#include "del.h"

CZo::CZo()
{
	vEx.reserve( 5 );
	l = 0;
}

CZo::CZo(
	const CZo & Z )
{
	int k;

	for( k = 0; k < (int)Z.vEx.size(); k++ )
	{
		if( k == (int)vEx.size() )
		{
			vEx.push_back( Z.vEx.at( k ) );
		}
		else
		{
			vEx.at( k ) = Z.vEx.at( k );
		}
	}

	l = Z.iL();
}

CZo & CZo::operator = (
	const CZo & Z )
{
	int k;

	if( this != &Z )
	{
		for( k = 0; k < (int)Z.vEx.size(); k++ )
		{
			if( k == (int)vEx.size() )
			{
				vEx.push_back( Z.vEx.at( k ) );
			}
			else
			{
				vEx.at( k ) = Z.vEx.at( k );
			}
		}

		l = Z.iL();
	}

	return *this;
}

void CZo::setL(
	int i )
{
	l = i;
}

void CZo::addEx(
	int iEx )
{
	vEx.push_back( iEx );
}

int CZo::iL() const
{
	return l;
}

int CZo::iNumberEx() const
{
	return (int)vEx.size();
}

bool CZo::bEx(
	int iEx ) const
{
	int i;

	for( i = 0; i < (int)vEx.size(); i++ )
	{
		if( vEx.at( i ) == iEx ) return true;
	}

	return false;
}

void CBl::setL(
	int iZo,
	int iL )
{
	if( iZo >= 0 && iZo < (int)vZo.size() && iL >= 0 )
	{
		vZo.at( iZo ).setL( iL );
	}
}

void CBl::addEx(
	int iZo,
	int iEx )
{
	if( iZo >= 0 && iZo < (int)vZo.size() )
	{
		vZo.at( iZo ).addEx( iEx );
	}
}

int CBl::iL(
	int iZo ) const
{
	if( iZo >= 0 && iZo < (int)vZo.size() )
	{
		return vZo.at( iZo ).iL();
	}
	return -1;
}

bool CBl::bEx(	
	int iZo,
	int iEx ) const
{
	if( iZo >= 0 && iZo < (int)vZo.size() )
	{
		return vZo.at( iZo ).bEx( iEx );
	}
	return false;
}

int CBl::iNumberZo() const
{
	return (int)vZo.size();
}

void CBl::addZo()
{
	CZo zo;
	vZo.push_back( zo );
}

void CBl::insertZo(
	int iZo )
{
	CZo zo;
	vZo.insert( vZo.begin() + iZo, zo );
}

std::vector<CZo>::iterator CBl::deleteZo(
	int iZo )
{
	return vZo.erase( vZo.begin() + iZo );
}

and a main.cpp:

#include "del.h"

int main()
{
	CBl bl;

	bl.addZo();
	bl.setL( bl.iNumberZo() - 1, 0 );
	bl.addEx( bl.iNumberZo() - 1, 110 );

	bl.addZo();
	bl.setL( bl.iNumberZo() - 1, 2 );
	bl.addEx( bl.iNumberZo() - 1, 110 );
	bl.addEx( bl.iNumberZo() - 1, 7 );

	bl.addZo();
	bl.setL( bl.iNumberZo() - 1, 1 );
	bl.addEx( bl.iNumberZo() - 1, 110 );

	bl.addZo();
	bl.setL( bl.iNumberZo() - 1, 2 );
	bl.addEx( bl.iNumberZo() - 1, 110 );

	bl.deleteZo( 1 );
	return 0;
}

The issue is in the before-last line in main.cpp. Before the deletion of the element indexed as 1 (so the second element in the vector), the vector content is as follows:

vZo.at( 0 ).l = 0
vZo.at( 0 ).vEx( 0 ) = 110

vZo.at( 1 ).l = 2
vZo.at( 1 ).vEx( 0 ) = 110
vZo.at( 1 ).vEx( 1 ) = 7

vZo.at( 2 ).l = 1
vZo.at( 2 ).vEx( 0 ) = 110

vZo.at( 3 ).l = 2
vZo.at( 3 ).vEx( 0 ) = 110

After the deletion, I expect the following:

vZo.at( 0 ).l = 0
vZo.at( 0 ).vEx( 0 ) = 110

vZo.at( 1 ).l = 1
vZo.at( 1 ).vEx( 0 ) = 110

vZo.at( 2 ).l = 2
vZo.at( 2 ).vEx( 0 ) = 110

However, I instead get:

vZo.at( 0 ).l = 0
vZo.at( 0 ).vEx( 0 ) = 110

vZo.at( 1 ).l = 1
vZo.at( 1 ).vEx( 0 ) = 110
vZo.at( 1 ).vEx( 1 ) = 7

vZo.at( 3 ).l = 2
vZo.at( 3 ).vEx( 0 ) = 110

... the "l" element is correct, but the vEx is not. What am I missing?

Thanks in advance!

Are you sure you didn't invalidate your iterators when you called erase...Try reinitializing you iterators after your call to erase and see if it displays properly.

I understand erasing a vector element invalidates iterators - yet, in this case, I'm not relying on iterators. The issue has to do with data in one vector element found in another vector element after the erase call. Could this be related to destructors?

The problem stems from an explicit definition of the copy/assignment constructors:

CZo::CZo(
	const CZo & Z )
{
	int k;

	[B]vEx.clear();[/B]
	for( k = 0; k < (int)Z.vEx.size(); k++ )
	{
		if( k == (int)vEx.size() )
		{
			vEx.push_back( Z.vEx.at( k ) );
		}
		else
		{
			vEx.at( k ) = Z.vEx.at( k );
		}
	}

	l = Z.iL();
}

CZo & CZo::operator = (
	const CZo & Z )
{
	int k;

	if( this != &Z )
	{
		[B]vEx.clear();[/B]
		for( k = 0; k < (int)Z.vEx.size(); k++ )
		{
			if( k == (int)vEx.size() )
			{
				vEx.push_back( Z.vEx.at( k ) );
			}
			else
			{
				vEx.at( k ) = Z.vEx.at( k );
			}
		}

		l = Z.iL();
	}

	return *this;
}

... adding the "vEx.clear();" does the trick.

This article has been dead for over six months. Start a new discussion instead.