but maybe you posted a simplification of real code. So: I think that you
should also pay attention about *where* (i.e. which module) you
allocate/free data.
i.e. I think that if you allocate something in the heap from module X (e.g.
a given DLL), you should also free that in the *same* module X.
from module X, and free in module Y.
Post by David WebberNot particularly deep...
... and yes - I am particular to the point of pedantry about that sort of
thing.
But explaining the problem has given me an idea.
=========================
this warning.
// This seems to be necessary if the class derived from vector is to be
exported.
EXTERN_MZWN_API template class MZWN_API
std::allocator<CPercussionInstrument>;
EXTERN_MZWN_API template class MZWN_API std::vector<CPercussionInstrument>;
// class CPercussionSet
class MZWN_API CPercussionSet : public std::vector<CPercussionInstrument>
{
CPercussionSet();
CPercussionSet( const CPercussionSet &ps );
virtual ~CPercussionSet();
CPercussionSet & operator = ( const CPercussionSet &ps );
//....
};
=============
I am pretty sure the copy constructor, destructor, and assignment of
CPercussionInstrument are ok (I am checking). I *am* a little concerned
about exporting this class from the DLL, (in which the only instance is
global) and wondering if that is at the root of things. It may not be
being correctly destroyed when the DLL is unloaded - though the destructor
*is* getting called.
Perhaps I should store a global; pointer to a CPercussionSet and explicitly
create and destroy it with new and delete. That way I'd have more control
over when it happens! I'll experiment.
Dave
--
David Webber
Author of 'Mozart the Music Processor'
http://www.mozart.co.uk
For discussion/support see
http://www.mozart.co.uk/mzusers/mailinglist.htm
Post by David WebberThanks! This is the way I am starting to think too - see other post. With
the class being global in the DLL I am not in control of where it is
constructed and destroyed. I propose to do something about that tomorrow -
it's late now.
Dave
--
David Webber
Author of 'Mozart the Music Processor'
http://www.mozart.co.uk
For discussion/support see
http://www.mozart.co.uk/mzusers/mailinglist.htm
.
Post by David WilkinsonWhat happens if you call clear() on your vector from somewhere else
(like ExitInstance()) rather than waiting for your derived destructor to
do it.
Actually, I don't think calling clear() from the destructor is
necessary, because the destructors of the contained objects are
automatically called by the std::vector destructor. I think the problem
is that your derived constructor is getting called too late relative to
the leak reporting mechanism.
--
David Wilkinson
Visual C++ MVP
Post by David ChingThat's what I thought also, but then why would it only start happening
recently when nothing has changed?
-- David
Post by Doug Harrison [MVP]On Wed, 10 Oct 2007 21:37:33 +0100, "David Webber"
That is the key sentence.
For some reason, your non-MFC DLL is loading before the MFC DLL now, and
during program termination, MFC is calling its "dump_spurious_leaks()"
function before your DLL has gotten the chance to destroy its globals.
http://groups.google.com/group/microsoft.public.vc.mfc/msg/990674e598690af9
http://groups.google.com/group/microsoft.public.vc.language/msg/6b90e68f21529e56
--
Doug Harrison
Visual C++ MVP
Post by David WebberI do that anyway - which is another puzzle.
That is a puzzle too - unless I have accidentally changed a setting in the
project which causes it to be reported. I don't *think* I have.
It isn't very serious. It is a bit of memory which should be used unchanged
(mostly) for the duration of the program, so having the system free it on
exit, isn't a disaster. But it's sloppy and I just *hate* it!
[The only time the memory is changed is when someone changes language
options: the instruments are unloaded and reloaded with their names in the
new language.]
Dave
--
David Webber
Author of 'Mozart the Music Processor'
http://www.mozart.co.uk
For discussion/support see
http://www.mozart.co.uk/mzusers/mailinglist.htm
Post by David WebberThanks Doug,
That appears to explain just about everything. And it makes me very
happy, because it means I did not program a memory leak - and thus delays
the fall I expect following my pride in never doing so :-)
I try to avoid global objects like the plague and this was my only infection
in this DLL. Most of my stuff which really needs to be global is stored
as a static pointer in a class, and the object is created by my InitInstance
code and explicitly deleted on ExitInstance. Once Norbert had told me how
to find it, the coincidence of global object and (apparent) memory leak
started ringing alarm bells.
I am now restructuring to handle this object like the others - which should
cure it as the memory will be freed from a call made by the MFC module.
Onward and upward.
Dave
--
David Webber
Author of 'Mozart the Music Processor'
http://www.mozart.co.uk
For discussion/support see
http://www.mozart.co.uk/mzusers/mailinglist.htm
Post by David WebberAll fixed now - thanks again to everyone.
Dave
--
David Webber
Author of 'Mozart the Music Processor'
http://www.mozart.co.uk
For discussion/support see
http://www.mozart.co.uk/mzusers/mailinglist.htm
Post by Giovanni DicanioThanks to you because we (or at least, I) learnt important lessons from your
post, like how super-important is to avoid global variables.
Giovanni
Post by David WilkinsonIn that case, it seems to me that the leak must be the memory allocated
for std::vector itself, rather than any memory internal to your CMyThing
objects.
What happens if you also shrink the vector to zero capacity (using the
swap trick)?
--
David Wilkinson
Visual C++ MVP
Post by David WebberI am rather concerned that I might know why. Well -ish. As I have an MFC
program with no main(), I put the _CrtSetBreakAlloc in the CWinApp drived
class constructor.
If the global vector object in the DLL was being constructed before the
CWinApp was constructed, it couldn't have actually stopped the program on
the vector's constuctor. The fact that it stopped when something was added
to the vector may have been a complete coincidence - in which case I've had
a monumental bit of luck :-(
So where does one put _CrtSetBreakAlloc to guarantee it is invoked before
absolutely anything is constructed?
Dave
--
David Webber
Author of 'Mozart the Music Processor'
http://www.mozart.co.uk
For discussion/support see
http://www.mozart.co.uk/mzusers/mailinglist.htm
Post by David WebberYes I have told myself that many times. It is my punishment for not taking
enough notice :-)
Dave
--
David Webber
Author of 'Mozart the Music Processor'
http://www.mozart.co.uk
For discussion/support see
http://www.mozart.co.uk/mzusers/mailinglist.htm
Gio
Post by David WilkinsonConstructing an empty vector does not assign any memory. When you add
things to it, the vector assigns memory and there may be additional
memory owned by the objects being placed in the vector.
I am not an expert on _CrtSetBreakAlloc(). I have always just used the
MFC DEBUG_NEW and have always been able to get rid of any leaks it
reported. But I don't use global objects.
--
David Wilkinson
Visual C++ MVP
Post by David ChingThere is another way.
http://msdn2.microsoft.com/en-us/library/w2fhc9a3(VS.80).aspx describes
setting the _crtBreakAlloc variable to the desired value instead of calling
_CrtSetBreakAlloc(). So just step into your code in the debugger so it
stops at the entrypoint, then set this variable in the watch window.
OTOH, I'm not sure if it's too late once you step into your code... global
vars might have already been init. But you can try it.
BTW, I'm not sure why it's any concern because this is not a true memory
leak in that the memory is freed when the app is exited anyway. I
understand you don't like to see the mem leak output though, since it makes
it easy to ignore true memory leak output.
-- David
Post by David ChingYour CWinApp derived class is a global object! :-)
-- David
Post by David WebberI'm not sure in what sense you mean this. Obviously if I put
CMyVector v;
Then &v will tell me where it is and sizeof v will tell me how big it is.
Ok, it is not being assigned dynamically but as a Global variable it sits
there and does not go out of scope until the program ends. In fact I have
always been rather vague on at what point its memory will be freed up,
because I have never really needed to know - until now :-)
But each will have its own block of assigned memory and I only got 1 leak
with 200 odd objects.
I too am a believer in DEBUG_NEW but this was happening in a non-MFC DLL.
Dave
--
David Webber
Author of 'Mozart the Music Processor'
http://www.mozart.co.uk
For discussion/support see
http://www.mozart.co.uk/mzusers/mailinglist.htm
Post by Giovanni DicanioYes, I was thinking about app class, too.
Maybe, in an elegant object-oriented designed system, the app instance
should be the only global object, and every other object should be created
by the app.
Giovanni
Yes, but I do not think its constructor assigns any memory.
--
David Wilkinson
Visual C++ MVP
it is fine if both modules link to the same CRT DLL. Given that David is
sharing C++ classes between modules, it is pretty much required.
--
Doug Harrison
Visual C++ MVP
Post by Doug Harrison [MVP]On Thu, 11 Oct 2007 11:40:20 +0200, "Giovanni Dicanio"
I hope there is a better reason than to avoid spurious leak reporting by
MFC. :) It's not just "globals"; this problem affects any object that is
destroyed after MFC calls its "cause_spurious_leak_report()" function. For
example, MFC would have caused the same problem if the OP's vector had been
a static data member of one of the classes in his DLL.
When I said "That is the key sentence," the implied second part was,
"...that helps me identify the problem." I did not mean that having a
global object was the problem, just that "non-MFC DLL", "global object",
and mysterious "memory leaks" remind me of this long-standing MFC bug.
--
Doug Harrison
Visual C++ MVP
Post by David WilkinsonBut only heap memory contributes to memory leaks, yes? If the objects
you put in your vector do not themselves assign heap memory (i.e. use
new internally) they will not contribute to memory leaks. The only
possible leak will come from the memory assigned by the vector itself.
And this should be released by the destructor, because std::vector is a
well-behaved RAII class.
I think the problem is just that the destructor of your global object is
getting called too late (and Doug thinks so also, so this must be right...).
--
David Wilkinson
Visual C++ MVP
Post by David WebberI wasn't sure of that.
Yes, it makes sense.
Dave
--
David Webber
Author of 'Mozart the Music Processor'
http://www.mozart.co.uk
For discussion/support see
http://www.mozart.co.uk/mzusers/mailinglist.htm