15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Weirdness retrieving object from CTypedPtrMap

Ted -- tward@geographix.com
Wednesday, August 14, 1996

Enviroment: VC++ 4.1 and Windows NT 4.0 beta 2

I have a CTypedPtrMap which I am using to store CMapStringToString 
objects.
The weird thing is that to retrieve a stored CMapStringToString object, I 
have to pass in a pointer after casting it to a reference.
If I pass in a reference, the members don't get initialized.  Trying to 
pass in a pointer, or reference to a pointer gives me an error.
Is this code safe?  Am I doing something wrong?

class MyClass
{
	...
	MyFunc(const CString&, const CString&);
	// Shared array of map tables.
	CTypedPtrMap  mMaps;
	...
}

BOOL MyClass::MyFunc(const CString& TableName, const CString& Key)
{
	BOOL b;

	CMapStringToString* Map;	// DECLARE A POINTER

	// Get the map object if it has already been loaded and stored.
	b = mMaps.Lookup(TableName, (CMapStringToString&)Map);	// CAST IT TO A 
REFERENCE

	// Load the map if it is not already present.
	if (b == FALSE)
	{
		// Create a map object.
		Map = new CMapStringToString;

		// Fill in the map.
		LoadMap(TableName, Map);

		// Store our map into our map collection.
		mMaps.SetAt( TableName, Map );
	}

	CString OutputValue;
	b = Map->Lookup( Key, OutputValue );

	return b;
}



Mike Blaszczak -- mikeblas@nwlink.com
Saturday, August 17, 1996

At 08:28 AM 8/14/96 -0600, you wrote:
>Enviroment: VC++ 4.1 and Windows NT 4.0 beta 2

>I have a CTypedPtrMap which I am using to store CMapStringToString 
>objects.

> CTypedPtrMap  mMaps;

You can't do that.  Your code isn't safe. It won't compile under MFC 4.2
because we put the screws down on the CTypedPtr classes and now they
won't anymore take bogus arguments.

Your declaration is wrong because CMapStringToPtr maps between a valued
class and a pointer to some CObject-derived thing. But you've provided a
non-pointer data type for your VALUE parameter, and the underlying
CMapStringToPtr donesn't know how to store or copy or recreate a complete
object--it only knows how to manage pointers to complete object.  (Hence
the name CMapStringTo_Ptr_!)

>The weird thing is that to retrieve a stored CMapStringToString object, I 
>have to pass in a pointer after casting it to a reference.

Whoa.  You've hacked in there a cast that's dangerous and not very good.

I think you should consider using something more along the lines of this:

  CTypedPtrMap  mMaps;

You'll have to do some memory management yourself (eg, call new to get
a CMapStringToString object before you SetAt(), and call delete after
you call RemoveKey()).  

and the prototype for CTypedMapPtr::Lookup() looks like this:

   BOOL Lookup(BASE_CLASS::BASE_ARG_KEY key, VALUE& rValue) const;

which means that, for your declaration, mMaps will need to take
a reference to a CMapStringToString object.

>If I pass in a reference, the members don't get initialized. 

Right--because the CMapStringtoPtr class that's doing all the work only
knows how to handle pointers, not whole complete objects.

Strictly, the way you declared mMaps, means that you wanted to do this:

>BOOL MyClass::MyFunc(const CString& TableName, const CString& Key)
>{      BOOL b;
>	CMapStringToString Map;	// DECLARE A POINTER
>	b = mMaps.Lookup(TableName, Map);

and that's just a fantastic waste of time. You'd be copying a whole
map --all of its elements, all of the structure that lives inside of
it, just to do one little lookup!  Your MyFunc() function would be
incredibly slow. (When I play my bass, my funk gets faster the
more I practice.)

So, I think you should rewrite your declaration like this:

class MyClass
{       // ... other stuff ...
	MyFunc(const CString&, const CString&);
	CTypedPtrMap  mMaps;
};

and I think you should rewrite MyClass::MyFunc() like this:

BOOL MyClass::MyFunc(const CString& TableName, const CString& Key)
{
	BOOL b;
	CMapStringToString* pMap;
	b = mMaps.Lookup(TableName, pMap);
	if (b == FALSE)
	{
		pMap = new CMapStringToString;
		LoadMap(TableName, pMap);
		mMaps.SetAt(TableName, Map);
	}
	CString OutputValue;
	b = pMap->Lookup( Key, OutputValue );
	return b;
}

and you'll have better luck.  You'll need to change other parts of your
code, though: make sure you review how LoadMap() is prototyped, and figure
out how you'll destroy maps without leaking any memory.



.B ekiM
http://www.nwlink.com/~mikeblas   <--- trip report central
1995 Honda VFR750F (Serial number 00050!)  4 Corners 1996!
1987 Yamaha FZ700 (damaged)                AMA, HRC, VFROC
     These words are my own: I do not speak for Microsoft.





| Вернуться в корень Архива |