Virtual Methods Question

P

Peter_Julian

| On Sun, 05 Mar 2006 02:11:19 -0500, Peter_Julian wrote:
|
| One more thought...
|
| >
| > Every cycle through the above program will leak memory since delete p
was
| > never called to invoke C's d~tor (of course, debug mode may help
depending
| > on your debugger). If you still don't think thats undefined behaviour:
write
| > a function that leaks a new allocation and loop through it a few
thousand
| > times in release mode.
| >
| > Anything could happen, it may format your hard drive, it might crash
your
| > OS, it may do nothing else except lower your resources. That, in effect,
is
| > the definition of undefined behaviour.
|
| Consider the following code:
|
| #include <list>
|
| typedef std::list<unsigned char*> MyList;
|
| int main()
| {
| MyList l;
|
| // Allocate the world.
| try
| {
| for (;;)
| {
| l.push_back(new unsigned char[1024]);
| }
| }
| catch(...)
| {
| }
|
| // Release the world.
| for (MyList::iterator i = l.begin(); i != l.end(); ++i)
| {
| delete [] *l;
| }
| }
|
| This code will (in theory) use up a tremendous amount of memory, only
| stopping when it is no longer able to allocate memory. Following the logic
| you expressed above, since it's unclear what the OS will do when it gets
| low on memory, then the above code exhibits "undefined behavior" (I'm
| setting up the same conditions, more or less, that the offending
| non-delete code had). It could, according to you, format the hard drive.

Not..

A computer that appropriately allocates and deallocates *all* of its memory
is low in resources at that very moment, thats all. Your arguement is not
the same. There is a huge difference between a program that runs out of
allocation space and one that permanently leaks it. The former renders a
known machine state and the latter does not.

As you've found out, the try block unwinds the stack only. That try block,
and much less a program, is unable to recover from a memory leak if you do
not deallocate the elements (the pointers would be lost forever).
Once the pointers are lost, no deallocation is possible unless you implement
placement new and an allocation pool (which is what debug mode does).

Or do i need to remind you that deallocating the pointer itself from the
stack does not deallocate the newed pointee?

Let me artificially induce a simulated memory allocation failure for you
after the tenth allocation.
Go ahead, comment out the %deallocations% section and then explain to me how
thats not undefined behaviour. That, after all, has been your arguement
until now.
____
#include <iostream>
#include <ostream>
#include <vector>
#include <list>
#include <stdexcept>

class N
{
int m_n;
std::vector<int> vn;
public:
N(int n) : m_n(n), vn(1024, 0)
{
if (m_n > 9) throw std::bad_alloc("out of mem !!!");
std::cout << "\nN()";
}
~N() { std::cout << "\n~N()"; }
};

int main()
{
std::list< N* > ln;
try
{
// allocations
for (int i = 0;; ++i)
{
ln.push_back(new N(i));
}
}
catch (const std::exception& e)
{
std::cout << "\nerror: " << e.what();
}

// size()
std::cout << "\n# of elements in list = " << ln.size();

// deallocations
typedef std::list< N* >::iterator LIter;
LIter liter = ln.begin();
for( liter; liter != ln.end(); ++liter)
{
delete *liter;
}

return 0;
}

/*

N()
N()
N()
N()
N()
N()
N()
N()
N()
N()
error: out of mem !!!
# of elements in list = 10
~N()
~N()
~N()
~N()
~N()
~N()
~N()
~N()
~N()
~N()

*/
____

|
| And yet (assuming I coded it right off the top of my head) all new's are
| paired with delete's. So how to identify the "undefined behavior"?

The program does not produce undefined behaviour since deallocation takes
place. You answered your own question. However, you've missed a critical
point... what if class N was a derived class?

Yes, thats right, what if we didn't modify main() in any way and derived
from a base class? hmm?

|
| Again, even though the effect of the above code on an OS is not
| necessarily predictable, it is not "undefined behavior" as defined by the
| C++ standard. So the effect of a memory leak on the OS is immaterial since
| the above code, which has no undefined behavior as defined by the C++ spec
| duplicates the conditions you described.
|
| - Jay
|

Thats not so, the programs you have described until now are ones without
deallocations. This program does not leak resources. Thanks, but you've
basicly proven the point i was making.

Now, lets start dealing with the real issue: shall we? I like to stick to my
guns.

If class N above were a derived class and its base class did not have a
virtual d~tor, deallocating the class N elements would leak the base class
component at each iteration. That's the undefined behaviour i was alluding
to.

Try it! add a base class with a non-virtual destructor, derive class N from
it, and test the theory with output in the base class d~tors. Pay attention.
I'm talking of a derived N *with* deallocation.

Hmm, undefined behaviour takes a whole new meaning then, doesn't it? delete
pointer is incapable of invoking the base class d~tor unless its virtual.
Thats a fact that needs to be viewed with great respect in C++ since
debugging for it when the client calls is a nightmare.

That is why, for example, deriving from the STL containers is not
recommended. Their destructors are not virtual.
Ya learn something every day, thats what makes life cool.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top