Desctruction of objects inside a static nested map holding pointers

J

jayaramganapathy

Hello friends,

I have a map like std::map< std::string , std::map<std::string,
std::string>* > EpPropCache::propertyCache ; (This is a static
instance and taken from *.cpp file)

As you can see the value is a pointer to another map. I do new of
std::map<std::string, std::string> and add the pointer to the map.

Do I have to delete the map objects which I create with new , which I
store on the static map instance?

Or
Will the destructor of the map be called when the program exists? In
that case I should be able to see log messages.

Thanks & Regards,
Jayaram
 
A

alan

Hello friends,

I have a map like std::map< std::string , std::map<std::string,
std::string>* > EpPropCache::propertyCache ; (This is a static
instance and taken from *.cpp file)

As you can see the value is a pointer to another map. I do new of
std::map<std::string, std::string> and add the pointer to the map.

Do I have to delete the map objects which I create with new , which I
store on the static map instance?
Yes.

Alternatively, use boost::shared_ptr<std::map<std::string,
std::string> >, which will automatically release them. Just make sure
that, except for initializing a shared_ptr (and initializing only from
a new), you do not, ever, assign a shared_ptr from a plain old
pointer. shared_ptr to shared_ptr is what you should always do. Also
avoid getting a plain pointer from a shared_ptr, because it raises the
question for later programmers - should the plain pointer be deleted
or no?
Or
Will the destructor of the map be called when the program exists? In
that case I should be able to see log messages.
Yes, if it exits. If it sits running for a long time instead, it
won't.
 
J

jayaramganapathy

On Nov 23, 9:55 pm, (e-mail address removed) wrote:> Hello friends,




Yes.

Alternatively, use boost::shared_ptr<std::map<std::string,
std::string> >, which will automatically release them. Just make sure
that, except for initializing a shared_ptr (and initializing only from
a new), you do not, ever, assign a shared_ptr from a plain old
pointer. shared_ptr to shared_ptr is what you should always do. Also
avoid getting a plain pointer from a shared_ptr, because it raises the
question for later programmers - should the plain pointer be deleted
or no?




Yes, if it exits. If it sits running for a long time instead, it
won't.






- Show quoted text -

Well as of now I cannot use Boost because to get those libraries into
projects I will require lot of approvals.
How can I ensure that it is getting destroyed?

You told Yes. Then at what point I should release them?
Do I have to iterate over the outer map and delete the nested maps and
then invoke a clear on the outer map?

Thanks and Regards,
Jayaram
 
K

Kai-Uwe Bux

Hello friends,

I have a map like std::map< std::string , std::map<std::string,
std::string>* > EpPropCache::propertyCache ; (This is a static
instance and taken from *.cpp file)

As you can see the value is a pointer to another map. I do new of
std::map<std::string, std::string> and add the pointer to the map.

Do I have to delete the map objects which I create with new , which I
store on the static map instance?

If you want to destroy the pointees and deallocate the memory, you have to
delete each pointer that you newed.
Or
Will the destructor of the map be called when the program exists? In
that case I should be able to see log messages.

The destructor of an object is called when the object goes out of scope. If
the map is static, its destructor will be called sometime before the
program exits. At this point, all entries in the map have their destructors
called. Those entries have the type

std::pair< std::string const, std::map<...> * >

The destructor of that, in turn will invoke the destructor of

std::map< std::string, std::string > *

which does a null-op. In particular, the destructor of the pointee will not
be called and the memory will not be deallocated. So if you want to destroy
all these objects and deallocate the memory, you have to do it by hand.


The remaining question is whether you _want_ to call the destructors of all
those strings and maps involved and whether you _want_ to deallocate all
associated memory, or whether you trust the OS to reclaim memory after the
program stops. Note that the objects in question do not allocate any
non-memory resources.


Best

Kai-Uwe Bux
 
K

Kai-Uwe Bux

Hello friends,

I have a map like std::map< std::string , std::map<std::string,
std::string>* > EpPropCache::propertyCache ; (This is a static
instance and taken from *.cpp file)

As you can see the value is a pointer to another map. I do new of
std::map<std::string, std::string> and add the pointer to the map.

Do I have to delete the map objects which I create with new , which I
store on the static map instance?

Or
Will the destructor of the map be called when the program exists? In
that case I should be able to see log messages.

Oops, I missed this bit about log messages. Why do you expect to see any?
The code-snippets you have shown do not indicate that any logging takes
place upon destruction of the map: the map destructor is not going to do
any logging.
 
A

alan

Well as of now I cannot use Boost because to get those libraries into
projects I will require lot of approvals.
Bummer. I *think* shared_ptr will be included in standard C++ soon,
but if upgrading to a hopefully standards-compliant C++ compiler will
also require lot of approvals, then bummer bummer. See also if you
can more easily get a tr1 version of your compiler; tr1 has a
shared_ptr in std::tr1:: too.

On the other hand, maybe you should just get the approvals -
shared_ptr may very well be worth the effort (think of the shared_ptr
as the whole point of Boost; everything else in Boost is just gravy).
This will of course vary depending on how difficult it is to get
approval.

IIRC Boost has a permissive license, allowing you to release binary
code without sources and with a license of your own (although if you
do release sources, I think you must properly include the Boost
license with the Boost code). Check your organization's lawyer if you
have to.
How can I ensure that it is getting destroyed?

You told Yes. Then at what point I should release them?
At the point where you would delete the outer map.

If the outer map is a class member, then in the destructor for the
class. Just make sure that any object of that class will end up being
deleted.

If the outer map is a local variable, then just before the function
exits. Remember to delete it at *each* function exit, if the function
has/will have multiple exit points. Remember to note this done
somewhere so that future programmers will remember to delete them if
they add a new exit point. And remember to wrap possibly exception-
throwing code with a try{}catch(){}, since exceptions are another exit
point for your function; delete it on the catch. Or forget all that
and start filling in the forms to get approval for boost/tr1.

If the outer map is a static/global object - I'm not sure. Most OS's
will free any unfreed memory in your program, but you did mention
something about logs. You'll have to wait for a language lawyer or
someone more qualified than me to tell you whether the destructors
will be called; I have the feeling they don't.

Do I have to iterate over the outer map and delete the nested maps and
then invoke a clear on the outer map?
Yes, except I think you'd invoke then invoke a delete on the outer
map. Or maybe not, if, say, it's a local variable. I'm not 100%
sure, since I use shared_ptr.
 
T

Tadeusz B. Kopec

Bummer. I *think* shared_ptr will be included in standard C++ soon, but
if upgrading to a hopefully standards-compliant C++ compiler will also
require lot of approvals, then bummer bummer. See also if you can more
easily get a tr1 version of your compiler; tr1 has a shared_ptr in
std::tr1:: too.

On the other hand, maybe you should just get the approvals - shared_ptr
may very well be worth the effort (think of the shared_ptr as the whole
point of Boost; everything else in Boost is just gravy). This will of
course vary depending on how difficult it is to get approval.

If I couldn't use boost::shared_ptr nor equivalent I'd rather make my own
reference counted smart pointer than delete those maps manually.
 
A

alan

If I couldn't use boost::shared_ptr nor equivalent I'd rather make my own
reference counted smart pointer than delete those maps manually.
True. I was going to suggest that too if getting approval is indeed
*that* difficult.

In all likelihood, taking the effort to create a smart pointer is a
good investment.

In case the OP is curious, in order to properly create a shared_ptr-
style smart pointer, you need to make sure that it is "copy-
constructible" and "assignable". Also, you must make sure that the
copy constructor (i.e.
my_shared_ptr<>::my_shared_ptr<>(my_shared_ptr<>&)) and the assignment
operator (my_shared_ptr<>& operator=(my_shared_ptr<>&)) use const
arguments - my_shared_ptr<>::my_shared_ptr<>(const my_shared_ptr<>&)
for example.

Boost doesn't implement it this way (I think), but if I were to
implement a shared_ptr, I would make the shared_ptr a handle to the
object. That is, I would create something like:

my_shared_ptr<T> ---> my_reference_count_ptr<T> ---> T object
(where ---> means "holds a pointer to")

my_reference_count_ptr is responsible for holding the pointer to the
object and keeping a reference count (preferably size_t, so that you
run out of memory before you can cause the count to wrap around). I
would suggest making its constructor private and making my_shared_ptr
a friend of my_reference_count_ptr.

my_reference_count_ptr's only ctor requires a plain old pointer to an
object, It initializes its pointer to the same value as that pointer,
and starts its reference count (I would prefer to init it at zero and
have my_shared_ptr handle incrementing that, but this is personal
preference). Its destructor then deletes whatever pointer it is
holding.

Others will prefer to include a "release" and "acquire" method in the
my_reference_count_ptr, but personally I don't, because I haven't
quite grokked yet what is safe to do after delete(this). If I were to
implement this I'd put them in my_shared_ptr.

When my_shared_ptr is constructed from a plain old pointer, it new's a
my_reference_count_ptr object and stores that into itself. Then it
calls its "acquire" method, which increments the reference count of
its my_reference_count_ptr (setting it to 1). This should be its
default constructor too, so put a default null pointer.

When my_shared_ptr is constructed from another my_shared_ptr
(my_shared_ptr<>::my_shared_ptr<>(const my_shared_ptr<>&)), it copies
the pointer from the input argument. Note that it copies just the
pointer, not the my_reference_count_ptr object itself; this object is
"shared" between the two my_shared_ptr's. Then it calls its acquire
method.

When my_shared_ptr is assigned from another my_shared_ptr
(my_shared_ptr<>& operator=(const my_shared_ptr<>&)), it first calls
its "release" method, which decrements the reference count of its
current my_reference_count_ptr; release then checks if the reference
count is zero, and deletes the my_reference_count_ptr object if so
(which will call the dtor for my_reference_count_ptr, which will
delete the object). Then it copies the pointer from the input
argument and calls its acquire method.

When my_shared_ptr is destructed, it simply calls its release method.

my_shared_ptr should overload the unary * and the -> operators. These
dereference and return, respectively, the pointer of its current
my_reference_count_ptr object.

Test your implementation well; including creating local variables for
it and doing exceptions; create a test class whose destructor has a
visible side effect (std::cout <<"destructor called!\n";) and see if
the destructor is indeed called.

Then you can use my_shared_ptr< map<std::string, std::string> > in
your outer map, and never worry about destructing them again.
 
J

James Kanze

On Nov 23, 9:55 pm, (e-mail address removed) wrote:> Hello friends,

Alternatively, use boost::shared_ptr<std::map<std::string,
std::string> >, which will automatically release them.

Or even better, perhaps, just skip the pointer. There's nothing
that says a map cannot contain maps. Something like:
std::map said:
Just make sure that, except for initializing a shared_ptr (and
initializing only from a new), you do not, ever, assign a
shared_ptr from a plain old pointer. shared_ptr to shared_ptr
is what you should always do.

Except when it might lead to a cycle. (Not a risk in this case,
of course.)
Yes, if it exits. If it sits running for a long time instead,
it won't.

If the object is static, he probably doesn't want the destructor
to be called before program exit. (Or if he wants the
destructor called before program exit, he shouldn't declare the
object static.)
 
J

James Kanze

Well as of now I cannot use Boost because to get those
libraries into projects I will require lot of approvals.

If you need a reference counted pointer, and can't use Boost,
it's pretty easy to implement a simplified version which would
be adequate for this case. I don't really think you need a
reference counted pointer here, however. Or any pointer, for
that matter.
How can I ensure that it is getting destroyed?

First: why do want to ensure that it is getting destroyed. I
often go out of my way to ensure that objects with conceptually
static lifetimes aren't destroyed. All destruction brings is
order of destructor problems.

Second: if you put maps, and not pointers, into the outer map,
everything will automatically be destructed, at least if you
return from main() or call exit(). (If you call abort(), or if
your program terminates because of a core dump, or a system
crash, or a power failure, or... destructors will not be
called.)
You told Yes. Then at what point I should release them?
Do I have to iterate over the outer map and delete the nested
maps and then invoke a clear on the outer map?

No. Static objects will automatically be destructed at (clean)
program shutdown.
 
J

James Kanze

If I couldn't use boost::shared_ptr nor equivalent I'd rather
make my own reference counted smart pointer than delete those
maps manually.

And I still don't understand the logic here. If the maps are
"owned" by the outer map, and should be destructed anytime the
outer map is destructed (or the element is removed from the
outer map), then the obvious solution is to put the maps
themselves into the outer map, rather than pointers to them. If
the elements have a lifetime independent of the outer map, then
you need to manage that explicitly.

Off hand, I can't think of any reasonable scenario where I would
use shared_ptr in a map. (That doesn't mean that they can't
exist, but it certainly isn't the usual case.)
 
J

jayaramganapathy

If you need a reference counted pointer, and can't use Boost,
it's pretty easy to implement a simplified version which would
be adequate for this case. I don't really think you need a
reference counted pointer here, however. Or any pointer, for
that matter.


First: why do want to ensure that it is getting destroyed. I
often go out of my way to ensure that objects with conceptuallystaticlifetimes aren't destroyed. All destruction brings is
order of destructor problems.

Second: if you put maps, and not pointers, into the outer map,
everything will automatically be destructed, at least if you
return from main() or call exit(). (If you call abort(), or if
your program terminates because of a core dump, or a system
crash, or a power failure, or... destructors will not be
called.)


No. Staticobjects will automatically be destructed at (clean)
program shutdown.

--
James Kanze (GABI Software) email:[email protected]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34- Hide quoted text -

- Show quoted text -

Well Guys, I am a slightly lazy fellow but won't compromise with
performance. I am working on a very old batch program where I did a
small caching framework.

My Caching architecture is
One table TAB1 in database holds a set of properties. I have grouped
various properties with a string PROPERTY_GROUP_ID. Then I have field,
value. which is inside the nested map.
I have a C++ class where I set the property group id to one member
variable. Then I call getProperty with a property name. The code hits
the outremap where PROPERTY_GROUP_ID is specified. If an entry is not
found then news a nested map entry with values of all field, value
pairs as key value for the property group.

The C++ calss do a new and delete frequently. But the C++ hold the my
MAP as static variable.
First I tried without pointers. Due to some issues of copy
constructors of nested map entries I beleive, I was not hitting the
cache properly. So I changed to pointers and printed the pointer. So
everything went fine. But I ended up creating memory leaks. But my
hope was since the map is a container there may be some logic like,
The map's destructor getting called. So map has to clean up. If the
maps key or value is a pointer then it invokes a delete on the
pointer. I have used only new. No malloc. So I guess delete operator
should be fine if the map holds a pointer. Is C++/STL smart enough to
do that? So gave a try.

The possible solution I can think of is
1) If I can override map destrutor then I can do my stuff of cleaing
and then the standard map cleaup.( This is a dream)
2) inherit the map and create my own map and crete its staic objevt
inside my class.
3) Create a wrapper clas against map and make it static and in its
destructor clean up the map
4) Do additional code for a geniric singleton pattern for solution two
or three and use it happily in future.

What is C++ gurus advice?

Thanks & Regards,
Jayaram Ganapathy
 
J

James Kanze

The C++ class do a new and delete frequently. But the C++ hold the my
MAP as static variable.
First I tried without pointers. Due to some issues of copy
constructors of nested map entries I beleive, I was not hitting the
cache properly.

I'm not sure what you mean here, but there is a requirement that
the map types be copiable. If the identity of the objects in
the map is important, then you need pointers. But normally, the
identity of an std::map is not important. And std::map has an
appropriate copy constructor. So it shouldn't be a problem.
So I changed to pointers and printed the pointer. So
everything went fine. But I ended up creating memory leaks.

What do you mean by memory leaks?
But my hope was since the map is a container there may be some
logic like, The map's destructor getting called. So map has to
clean up. If the maps key or value is a pointer then it
invokes a delete on the pointer. I have used only new. No
malloc. So I guess delete operator should be fine if the map
holds a pointer. Is C++/STL smart enough to do that? So gave a
try.
The possible solution I can think of is
1) If I can override map destrutor then I can do my stuff of cleaing
and then the standard map cleaup.( This is a dream)
2) inherit the map and create my own map and crete its staic objevt
inside my class.
3) Create a wrapper clas against map and make it static and in its
destructor clean up the map
4) Do additional code for a geniric singleton pattern for solution two
or three and use it happily in future.
What is C++ gurus advice?

My recommendations are still 1) make it work without pointers,
and 2) don't worry about the "leaks". If you don't remove
objects from the map other than at the end of the program, it
doesn't leak memory.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top