class A
{
class Container;
static Container container;
public:
~A();
};
Assume that A::~A() does something with A::container (eg. removes or
changes an element from it or whatever).
Also assume that somewhere else there's a global instantiation of A
like this:
namespace { A anObject; }
The question is: Is it guaranteed that 'anObject' will be destroyed
before 'A::container'?
Because, obviously, if 'A::container' is destroyed first, then the
destructor of 'anObject' will be accessing a destroyed Container object.
If it's not guaranteed, then how can one use static members safely?
This is a declaration. Where is the definition?
>
> public:
> ~A();
> };
>
> Assume that A::~A() does something with A::container (eg. removes or
> changes an element from it or whatever).
>
> Also assume that somewhere else there's a global instantiation of A
> like this:
>
> namespace { A anObject; }
>
> The question is: Is it guaranteed that 'anObject' will be destroyed
> before 'A::container'?
No, it's not guaranteed. What's guaranteed, however, is that if they
are created in some order, then they are destructed in the reverse order.
> Because, obviously, if 'A::container' is destroyed first, then the
> destructor of 'anObject' will be accessing a destroyed Container object.
Yep.
> If it's not guaranteed, then how can one use static members safely?
Apparently you need 'A::container' to be a singleton. See any of the
existing implementations of that pattern. Most simple ones actually
create the singleton on demand (in freestore) and never destroy it.
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
> > class A
> > {
> > class Container;
> > static Container container;
> This is a declaration. Where is the definition?
You ask the necessary question.
> > public:
> > ~A();
> > };
> > Assume that A::~A() does something with A::container (eg.
> > removes or changes an element from it or whatever).
> > Also assume that somewhere else there's a global
> > instantiation of A like this:
> > namespace { A anObject; }
> > The question is: Is it guaranteed that 'anObject' will be
> > destroyed before 'A::container'?
> No, it's not guaranteed. What's guaranteed, however, is that
> if they are created in some order, then they are destructed in
> the reverse order.
And then answer it without knowing the answer. If the
definition is in the same translation unit, before this
statement, it is guaranteed. Otherwise not.
> > Because, obviously, if 'A::container' is destroyed first,
> > then the destructor of 'anObject' will be accessing a
> > destroyed Container object.
> Yep.
I'd have to see the source of A::~A() first, before I was so
categorical:-). And also the declaration of Container. If
A::~A() doesn't access container, there's no problem. Same
thing if Container has a trivial destructor. (I'll admit that
with a name like Container, it's highly unlikely that the
destructor is trivial.)
> > If it's not guaranteed, then how can one use static members
> > safely?
> Apparently you need 'A::container' to be a singleton. See any
> of the existing implementations of that pattern. Most simple
> ones actually create the singleton on demand (in freestore)
> and never destroy it.
That's often the simplest and most appropriate solution. If
Container is a more general class (e.g. an std::vector), then
you can wrap it in a simple function to ensure the same
behavior. Another solution is to ensure that Container has a
trivial destructor.
--
James Kanze
> On Nov 27, 2:49 pm, Victor Bazarov <v.Abaza...@comAcast.net> wrote:
>> Juha Nieminen wrote:
>> > Assume we have a class like this:
>
>> > class A
>> > {
>> > class Container;
>> > static Container container;
>
>> This is a declaration. Where is the definition?
>
> You ask the necessary question.
>
>> > public:
>> > ~A();
>> > };
>
>> > Assume that A::~A() does something with A::container (eg.
>> > removes or changes an element from it or whatever).
>
>> > Also assume that somewhere else there's a global
>> > instantiation of A like this:
>
>> > namespace { A anObject; }
>
>> > The question is: Is it guaranteed that 'anObject' will be
>> > destroyed before 'A::container'?
>
>> No, it's not guaranteed. What's guaranteed, however, is that
>> if they are created in some order, then they are destructed in
>> the reverse order.
>
> And then answer it without knowing the answer. If the
> definition is in the same translation unit, before this
> statement, it is guaranteed. Otherwise not.
>
It is always guaranteed if i interpret the Standard correctly. 3.6.3/1:
"Destructors (12.4) for initialized objects of static storage duration
(declared at block scope or at namespace scope) are called as a result of
returning from main and as a result of calling exit (18.3). These objects
are destroyed in the reverse order of the completion of their constructor or
of the completion of their dynamic initialization."
You mean that if you want to make sure that a static member is never
accessed after it has been destroyed, you have to allocate it
dynamically and purposefully leak it?
Doesn't that make static members a bit useless?
How can you implement safely something like this?
// Header file
// -----------
class A
{
static std::vector<int> sharedContainer;
A(const A&);
A& operator=(const A&);
public:
A();
~A();
};
// Source file
// -----------
std::vector<int> A::sharedContainer;
A::A() { sharedContainer.push_back(0); }
A::~A() { sharedContainer.pop_back(); }
If somewhere else you have something like:
namespace { A a; }
then the constructor might be accessing an unconstructed std::vector,
and the destructor might be accessing a destroyed std::vector.
Construction safety could be ensured by changing the container to:
namespace
{
std::vector<int>& sharedContainer()
{
static std::vector<int> container;
return container;
}
}
But does that ensure that it's not accessed after it has been
destroyed? If not, how do you make sure it's not?
> public:
> A();
> ~A();
> };
> namespace { A a; }
Yes. And the push_back/pop_back mean that you can't use int[]
and static initialization:-).
> Construction safety could be ensured by changing the container to:
>
> namespace
> {
> std::vector<int>& sharedContainer()
> {
> static std::vector<int> container;
> return container;
> }
> }
> But does that ensure that it's not accessed after it has been
> destroyed? If not, how do you make sure it's not?
std::vector< int >&
sharedContainer()
{
static std::vector< int >* theOneAndOnly = new std::vecctor< int >;
return *theOneAndOnly;
}
The standard singleton idiom, in fact.
--
James Kanze
> You mean that if you want to make sure that a static member is
> never accessed after it has been destroyed, you have to
> allocate it dynamically and purposefully leak it?
That's the usual singleton idiom.
> Doesn't that make static members a bit useless?
Not really. At the application level, there are any number of
classes which simply can't be used before entering main (for
various reasons), and for which all instances will be destructed
before leaving main. No problem with static members here. It
generally only gets tricky for library code (where you don't
really know where it will be used), or a few special application
level classes.
--
James Kanze
So you mean that you have to deliberately introduce a memory leak if
you want to make sure the container is not accessed after it has been
destroyed?
Is there *really* no better way of doing it?
I would have never thought at a programming idiom requires deliberate
introduction of a memory leak into your program. Is it really the only way?
Look up the Alexandrescu-singleton
How about this:
class SharedContainer
{
public:
SharedContainer()
{
if ( 0 == Counter() )
{
c() = new Container;
}
++Counter();
}
~SharedContainer()
{
--Counter();
if ( 0 == Counter() )
{
delete c();
}
}
Container& GetContainer()
{
assert( NULL != c() );
return *c();
}
private:
Container *& c()
{
static Container *c = NULL;
return c;
}
int& Counter()
{
static int n = 0;
return n;
}
};
warning : I haven't tested this, but I am sure you got an idea ;)
--
ultrasound www.ezono.com
How are you defining "memory leak". I don't see anything which
could be qualified as a memory leak, with any of the usual
definitions.
The only useful definition is "memory which leaks"; i.e. which
is periodically reallocated, with previous allocations going
unused, so that the program grows indefinitely. That's not the
case here. I have seen it defined as memory which can no longer
be accessed, because there are no more pointers to it; the only
use I can think of for this definition is to prove that you
can't get a memory leak with garbage collection. But the above
doesn't leak by this definition either, since there's always a
pointer to it.
> Is there *really* no better way of doing it?
It being? And "better" meaning?
If the goal is to ensure that an object is not destructed (which
is what you want here), then I don't know of any better way of
doing it than using an allocation without a delete.
--
James Kanze
If one wants the singleton to be available until the program termination,
then one cannot destroy it from inside the program, it's as simple as
that. I would not call this a real memory leak as any decent OS will
reclaim the singleton memory immediately afterwards, during the process
termination.
Of course, one could define a safe order of destruction of all singletons
and ensure that they are destroyed properly before the program
termination, but this would only make the program slower and more error-
prone, with no positive effect whatsoever.
This is a typical confusion of the goal and the means. The "memory leak"
concept is just a means used for making the programs better, and not a
goal in itself.
Paavo
Where is the memory leak? You never allocate more than one, so
there can't be a memory leak.
> Is it really the only way?
If you want something available until all user defined
destructors have terminated, you can't invoke a user defined
destructor on it: either it has a trivial destructor, or you
don't destruct it. There are no other choices.
--
James Kanze
On the programs I work on, a memory leak is a fatal error. This
isn't a memory leak, however, by any definition of the word.
--
James Kanze
Sure it is, a conceivable definition is just "anything flagged as a
memory leak by the diagnostic tool I happened to use".
I tried to argue why such a definition would not be a useful one.
Regards
Paavo
[...]
> >> This is a typical confusion of the goal and the means. The
> >> "memory leak" concept is just a means used for making the
> >> programs better, and not a goal in itself.
> > On the programs I work on, a memory leak is a fatal error. This
> > isn't a memory leak, however, by any definition of the word.
> Sure it is, a conceivable definition is just "anything flagged as a
> memory leak by the diagnostic tool I happened to use".
But does any tool flag this as a memory leak? There's still a
pointer to the memory, so it is at most a "possible memory
leak".
> I tried to argue why such a definition would not be a useful
> one.
The only useful one is the one which uses leak in its everyday
sense, of course. A little bit constantly seeping out over
time. The only other one I've seen is "no remaining pointers to
the memory", which is sometimes used by Java advocates to
"prove" that Java can't leak memory.
Here, it's not so much a case of whether the definition is
useful or not; it's a case of using a totally arbitrary
definition which doesn't correspond to anything real. (I'm not
blaming Juha for this---he doubtlessly got it from somewhere.
But it's not an acceptable definition.)
--
James Kanze
> On Dec 7, 6:09 pm, Paavo Helde <myfirstn...@osa.pri.ee> wrote:
>> James Kanze <james.ka...@gmail.com> wrote in news:0cca4033-dfff-4c8f-
>> a33e-7baebbe6c...@j35g2000vbl.googlegroups.com:
>
> [...]
>> >> This is a typical confusion of the goal and the means. The
>> >> "memory leak" concept is just a means used for making the
>> >> programs better, and not a goal in itself.
>
>> > On the programs I work on, a memory leak is a fatal error. This
>> > isn't a memory leak, however, by any definition of the word.
>
>> Sure it is, a conceivable definition is just "anything flagged as a
>> memory leak by the diagnostic tool I happened to use".
>
> But does any tool flag this as a memory leak? There's still a
> pointer to the memory, so it is at most a "possible memory
> leak".
>
MSVC++ Debug heap facility (guided by _CrtSetDbgFlag() et al.) is
reporting things like this:
Detected memory leaks!
Dumping objects ->
{59831} normal block at 0x0C061168, 36 bytes long.
Data: < ����UI �����> 00 00 00 00 CD CD CD CD 55 49 00 CD CD CD CD CD
{59830} normal block at 0x0C0610E8, 68 bytes long.
Data: <�m �m > D8 6D 03 0C 08 05 06 0C D8 6D 03 0C 00 00 00 00
{59803} normal block at 0x0C060588, 36 bytes long.
Data: < ����UI �����> 00 00 00 00 CD CD CD CD 55 49 00 CD CD CD CD CD
{59802} normal block at 0x0C060508, 68 bytes long.
...
As far as I know, it reports all blocks which have been obtained from the
heap, and not explicitly freed by the time of check. A thing of interest
is that it does not call them "possible memory leaks".
>> I tried to argue why such a definition would not be a useful
>> one.
>
> The only useful one is the one which uses leak in its everyday
> sense, of course. A little bit constantly seeping out over
> time. The only other one I've seen is "no remaining pointers to
> the memory", which is sometimes used by Java advocates to
> "prove" that Java can't leak memory.
>
> Here, it's not so much a case of whether the definition is
> useful or not; it's a case of using a totally arbitrary
> definition which doesn't correspond to anything real. (I'm not
> blaming Juha for this---he doubtlessly got it from somewhere.
> But it's not an acceptable definition.)
Agreed.
Paavo
> > [...]
> >> >> This is a typical confusion of the goal and the means.
> >> >> The "memory leak" concept is just a means used for
> >> >> making the programs better, and not a goal in itself.
> >> > On the programs I work on, a memory leak is a fatal
> >> > error. This isn't a memory leak, however, by any
> >> > definition of the word.
> >> Sure it is, a conceivable definition is just "anything
> >> flagged as a memory leak by the diagnostic tool I happened
> >> to use".
> > But does any tool flag this as a memory leak? There's still
> > a pointer to the memory, so it is at most a "possible memory
> > leak".
> MSVC++ Debug heap facility (guided by _CrtSetDbgFlag() et al.) is
> reporting things like this:
> Detected memory leaks!
> Dumping objects ->
> {59831} normal block at 0x0C061168, 36 bytes long.
> Data: < ÍÍÍÍUI ÍÍÍÍÍ> 00 00 00 00 CD CD CD CD 55 49 00 CD CD CD CD CD
> {59830} normal block at 0x0C0610E8, 68 bytes long.
> Data: <Øm Øm > D8 6D 03 0C 08 05 06 0C D8 6D 03 0C 00 00 00 00
> {59803} normal block at 0x0C060588, 36 bytes long.
> Data: < ÍÍÍÍUI ÍÍÍÍÍ> 00 00 00 00 CD CD CD CD 55 49 00 CD CD CD CD CD
> {59802} normal block at 0x0C060508, 68 bytes long.
> ...
If there is still a pointer to the object with static lifetime,
I'd consider calling it a leak an error. Quality leak detecters
(like Purify) make the distinction. (To be fair to Microsoft,
the debug leak detector is just a simple hack, to help a little.
I don't think Microsoft claims that it is complete and thorough.
I suspect that it just looks at the heap and reports unfreed
objects, without trying to determine whether there are pointers
to them or not---the latter can be a major undertaking without
access to the source. But they really should change the label
to something like: "unfreed memory (possible leak?)".)
> As far as I know, it reports all blocks which have been
> obtained from the heap, and not explicitly freed by the time
> of check. A thing of interest is that it does not call them
> "possible memory leaks".
In fact, what it detects is unfreed memory, and not leaks.
Which is something useful, not too difficult to do, with little
or no impact on the runtime. (Programs under Purify run
significantly slower.) But they should correct the label.
--
James Kanze