map of pointers inside another map raise exception

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

Post Reply
User avatar
Emily W. Haley
Posts: 2
Joined: Wed May 13, 2020 7:33 pm

map of pointers inside another map raise exception

Post by Emily W. Haley »

Hi, All

I have created my own std::map wrapper because it makes some of my tasks simpler this way.
The code for the wrapper:

Code: Select all

//---------------------------------------------------------------------------
#ifndef MapListH
#define MapListH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <System.SysUtils.hpp>
#include "ClangCpp.h"
#include <string.h>
#include <map>
//---------------------------------------------------------------------------
//New Events
//---------------------------------------------------------------------------
template <class Key, class Value>
class TMapList
{
protected:
typedef std::pair<Key,Value> PairType;
typedef void __fastcall (__closure *TForEachItem)(Key Index, Value Item);
typedef void __fastcall (__closure *TItemClear)(Key Index, Value Item);
typedef typename std::map<Key,Value>::iterator TMapListIterator;

private:
//Events
TItemClear FOnItemClear;

//---------------------------------------------------------------------------
protected:
//Setters/Getters
virtual int __fastcall GetCount() const;
virtual void __fastcall SetElement(Key Index, const Value& Item);
virtual Value __fastcall GetElement(Key Index) const;
virtual void __fastcall SetElementByIndex(int Index, const Value& Item);
virtual Value __fastcall GetElementByIndex(int Index) const;
virtual Key __fastcall GetKeyByIndex(int Index) const;
virtual Key __fastcall GetKeyByValue(Value Item) const;

//Do Events Methods
virtual void __fastcall DoItemClear(Key Index, Value Item);

//---------------------------------------------------------------------------
public:
//Fields/Properties
mutable std::map< Key, Value> Map;

mutable typename std::map<Key,Value>::iterator Iter;
__property int Count = {read = GetCount};
__property Value Item[Key Index] = {read = GetElement, write = SetElement};
__property Value ItemByIndex[int Index] = {read = GetElementByIndex, write = SetElementByIndex};
__property Key KeysByIndex[int Index] = {read = GetKeyByIndex};
__property Key KeyByValue[Value Item] = {read = GetKeyByValue};

//Constructor / Destructor.
__fastcall TMapList() {FOnItemClear = nullptr;};
virtual __fastcall ~TMapList(void);

//Methods
virtual void __fastcall First() const;
virtual void __fastcall Last() const;
virtual void __fastcall IncIter();
virtual void __fastcall Add(Key Index, const Value& Item);
virtual bool __fastcall Exists(Key Index) const;
virtual typename std::map<Key,Value>::iterator __fastcall FindIter(Key Index) const;
virtual bool __fastcall Find(Key Index, Value& Item) const;
virtual bool __fastcall Find(Key Index) const;
virtual bool __fastcall TillEnd() const;
virtual bool __fastcall ValueExists(Value Item) const;
virtual Value __fastcall Delete(Key Index);
virtual bool __fastcall Empty() const;
//Methods
virtual void __fastcall ForEachItem(TForEachItem ForEachItemEvent);

virtual void __fastcall Clear();

inline bool operator == (const TMapList& MapListValue) const
{
return (Map == MapListValue.Map);
}
//--------------------------------

//Events
__property TItemClear OnItemClear= {read = FOnItemClear, write = FOnItemClear};
};
//---------------------------------------------------------------------------
typedef std::map<String,String> TStrsMap;

typedef std::pair<int,int> TIntToIntPair;
typedef std::pair<int,String> TIntToStrPair;
typedef std::pair<String,String> TStrToStrPair;
typedef std::pair<String,int> TStrToIntPair;

typedef TMapList<int,int> TIntToIntMap;
typedef TMapList<int,String> TIntToStrMap;
typedef TMapList<String,String> TStrToStrMap;
typedef TMapList<String,int> TStrToIntMap;
//---------------------------------------------------------------------------
template <class Key, class Value>
int __fastcall TMapList<Key,Value>::GetCount() const
{
return Map.size();
}
//---------------------------------------------------------------------------
template <class Key, class Value>
void __fastcall TMapList<Key,Value>::SetElement(Key Index, const Value& Item)
{
Map[Index] = Item;
}
//---------------------------------------------------------------------------
template <class Key, class Value>
Value __fastcall TMapList<Key,Value>::GetElement(Key Index) const
{
return Map[Index];
}
//---------------------------------------------------------------------------
template <class Key, class Value>
void __fastcall TMapList<Key,Value>::SetElementByIndex(int Index, const Value& Item)
{
Iter = Map.begin();
std::advance(Iter, Index);
Iter->second = Item;
}
//---------------------------------------------------------------------------
template <class Key, class Value>
Value __fastcall TMapList<Key,Value>::GetElementByIndex(int Index) const
{
Iter = Map.begin();
std::advance(Iter, Index);
return Iter->second;
}
//---------------------------------------------------------------------------
template <class Key, class Value>
Key __fastcall TMapList<Key,Value>::GetKeyByIndex(int Index) const
{
Iter = Map.begin();
std::advance(Iter, Index);
return Iter->first;
}
//---------------------------------------------------------------------------
template <class Key, class Value>
Key __fastcall TMapList<Key,Value>::GetKeyByValue(Value Item) const
{
Key res;

for (Iter = Map.begin(); Iter != Map.end(); ++Iter )
	{
	if (Iter->second == Item)
		{
		res = Iter->first;
		break;
		}
	}
return res;
}
//---------------------------------------------------------------------------
template <class Key, class Value>
void __fastcall TMapList<Key,Value>::DoItemClear(Key Index, Value Item)
{
if (FOnItemClear)
	FOnItemClear(Index, Item);
}
//---------------------------------------------------------------------------
template <class Key, class Value>
__fastcall TMapList<Key,Value>::~TMapList(void)
{
Clear();
}
//---------------------------------------------------------------------------
template <class Key, class Value>
void __fastcall TMapList<Key,Value>::First() const
{
this->Iter = this->Map.begin();
}
//---------------------------------------------------------------------------
template <class Key, class Value>
void __fastcall TMapList<Key,Value>::Last() const
{
this->Iter = this->Map.end();
}
//---------------------------------------------------------------------------
template <class Key, class Value>
void __fastcall TMapList<Key,Value>::IncIter()
{
++Iter;
}
//---------------------------------------------------------------------------
template <class Key, class Value>
bool __fastcall TMapList<Key,Value>::TillEnd() const
{
return (this->Iter != this->Map.end());
}
//---------------------------------------------------------------------------
template <class Key, class Value>
void __fastcall TMapList<Key,Value>::Add(Key Index, const Value& Item)
{
Map.insert(std::make_pair( Index, Item));
}
//---------------------------------------------------------------------------
template <class Key, class Value>
bool __fastcall TMapList<Key,Value>::Exists(Key Index) const
{
return Map.count(Index);
}
//---------------------------------------------------------------------------
template <class Key, class Value>
typename std::map<Key,Value>::iterator __fastcall TMapList<Key,Value>::FindIter(Key Index) const
{
return Map.find(Index);
}
//---------------------------------------------------------------------------
template <class Key, class Value>
bool __fastcall TMapList<Key,Value>::Find(Key Index, Value& Item) const
{
Iter = Map.find(Index);

if (Iter != Map.end())
	{
	Item = Iter->second;
	return true;
	}
else
	return false;
}
//---------------------------------------------------------------------------
template <class Key, class Value>
bool __fastcall TMapList<Key,Value>::Find(Key Index) const
{
Iter = Map.find(Index);
return (Iter != Map.end());
}
//---------------------------------------------------------------------------
template <class Key, class Value>
bool __fastcall TMapList<Key,Value>::ValueExists(Value Item) const
{
for (Iter = Map.begin(); Iter != Map.end(); ++Iter )
	{
	if (Iter->second == Item)
		return true;
	}
return false;
}
//---------------------------------------------------------------------------
template <class Key, class Value>
Value __fastcall TMapList<Key,Value>::Delete(Key Index)
{
Value temp = Item[Index];
Map.erase(Index);
return temp;
}
//---------------------------------------------------------------------------
template <class Key, class Value>
bool __fastcall TMapList<Key,Value>::Empty() const
{
return (GetCount() == 0);
}
//---------------------------------------------------------------------------
template <class Key, class Value>
void __fastcall TMapList<Key,Value>::ForEachItem(TForEachItem ForEachItemEvent)
{
for (Iter=Map.begin(); Iter !=Map.end(); ++Iter)
	{
	ForEachItemEvent(Iter->first, Iter->second);
	}
}
//---------------------------------------------------------------------------
template <class Key, class Value>
void __fastcall TMapList<Key,Value>::Clear()
{
if (Count > 0)
	{
	if (FOnItemClear)
		{
		for (Iter=Map.begin(); Iter !=Map.end(); ++Iter)
			{
			DoItemClear(Iter->first, Iter->second);
			}
		}

	Map.clear();
	}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
template <class Key, class Value>
class TPtrMapList : public TMapList<Key, Value>
{
public:
virtual __fastcall ~TPtrMapList(void)
{
this->Clear();
}

virtual void __fastcall Clear()
{
if (!this->Map.empty())
	{
	this->Iter = this->Map.begin();

	for (; this->Iter != this->Map.end(); ++this->Iter)
		{
		if (this->Iter->second != nullptr)
			delete this->Iter->second;
		}
	}

this->Map.clear();
}
};
//---------------------------------------------------------------------------
#endif
As you can see I have 2 TMapList classes one for normal types and another for pointers.
Then I have this code which raises an error when I user a TPtrMapList inside another TMapList like below:

Code: Select all

//Header
struct TTestObject
{
int ID;
String Name;
TStrToStrMap ActionsConditions;
};
typedef TMapList<String,TTestObject*> TTestObjectList;
typedef TMapList<String,TTestObjectList> TResourcesMapList;

class TForm1 : public TForm
{
__published:
...
public:
TResourcesMapList ResourcesMapList;

Code: Select all

void __fastcall TForm1::Btn1Click(TObject *Sender)
{
TTestObjectList ObjectList;
TTestObject* Obj = new TTestObject;

Obj->ID = 1;
Obj->Name = "AAA";

Obj->ActionsConditions.Add("CCC","");

ObjectList.Add("DDD",Obj);

ResourcesMapList.Add("Test", ObjectList); // Error raised here I think the destructor is called but why
I tried using references instead of pointers before but because I am filling the "TTestObjectList" with derived classes from "TTestObject" it was giving me errors as well during casting from base object inside the map to derived class, I tried dynamic_cast, static_cast, reinterpret_cast but nothing works always raises an exception when I use ay new data member from the derived classes.

Now this works fine with shared_ptr instead of using normal pointers but I want to know what am I doing wrong?

I am passing ObjectList as "const reference" shouldn't this pass the same object not make a copy, then why the destructor is called for the TPtrMapList at this point when I add it into another map?

Thanks
rlebeau
BCBJ Author
BCBJ Author
Posts: 1715
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA
Contact:

Re: map of pointers inside another map raise exception

Post by rlebeau »

Emily W. Haley wrote:As you can see I have 2 TMapList classes one for normal types and another for pointers.
Then I have this code which raises an error when I user a TPtrMapList inside another TMapList
I just answered this same question in the Embarcadero forum:

https://community.idera.com/developer-t ... 5365#95365
Remy Lebeau (TeamB)
Lebeau Software
Post Reply