Well I have a map like this :
std::map <string, CObject> ObjectList;
This will insert copies of strings and copies of CObject. std::string can
manage itself and is usually implemented using ref counting, so that's okay.
The thing is, it will also insert copies of CObjects. If CObject is not
implemented in a way that
1) copy construction is efficient and
2) copies are equivalent
the STL containers won't be of much use.
If copy construction is not efficient, you will have problems since at four
copies can be made by the various functions. For example,
map.insert(std::make_pair(key, value));
calls these (at least)
make_pair() takes key and value by value
pair's ctor makes copies of them
pair's cpy-ctor copies key and value
map::insert() copies key and value in container
So having an efficient copy-ctor is almost mandatory. Since all these
copies are made, if two copies are not equivalent, the object cannot be used
in containers. That is the case of your CObject class.
I have a function like this :
CObject* NewObject( char* Name, CArg* Arg)
{
std::string key = Name;
ObjectList[ key] = CObject( Name, Arg);
This line is very important. It first constructs a CObject (on the right
side) and then calls operator[] for ObjectList on the left side. This
operator returns a reference to the value having that key, but creates that
value if the key is not found. The only way it can create a new value is to
use the default constructor, which seems to be disabled in your class.
This is not the recommended way of inserting values in a std::map since it
is less efficient and can cause errors. You must first check if the key
exists. If it does, don't insert it, and if it doesn't, insert it :
// you should always typedef STL containers
typedef std::map <string, CObject> ObjectList;
ObjectList ol;
ObjectList::iterator itor = ol.find(key);
if ( itor == ol.end() )
{
// the key does not exist
ol.insert(std::make_pair(key, value));
}
else
{
// the key exists
}
return &ObjectList[Name];
return &(itor->second);
}
I tried to compile and it complained that there was no default constructor
for CObject
So I changed my constructor declaration to :
CObject::CObject( char* Name = "Default", CArg* Arg = NULL);
This kind of error is not generated because of the argument's values, but
because of the argument count. If the compiler complains that there is
default ctor available, its because somewhere you're calling the default
constructor, that is, you construct an object with no arguments.
Just to sse because I can't create it without a valid CArg pointer.
That would be a runtime error, not a compile-time error.
What? If your compiler accepts code that calls functions with the wrong
agument count, change the compiler.
Now, for the solution, you can do many things. The two more obvious would
be
1) put pointers in the map
2) change CObject's copy constructor and destructor
By putting pointers in the map, you solve all the problems related to
copying and destroying, at the cost of runtime speed, since you must
allocate the objects on the heap. There are some memory-related potential
problems, since _you_ are responsible for deleting the objects. To be sure,
you should use some kind of reference-counted pointers (a simple
hand-crafted one could work, but check out the boost library for
shared_ptr).
But I think the real solution would be to implement the reference counting
system in the CObject class itself, so that copies are equivalent. That
way, with
CObject o;
CObject p;
p = o;
'p' should be equivalent to 'o'. This implies two things : that p and o
must work the same way after being copied and that if one of them is
destroyed, the other can continue to work the same way. By using reference
counting, if p is destroyed before o for example, you can prevent p from
releasing resources if o needs them. That's the basics of reference
counting.
Jonathan