noob question - destructors - freeing memory...

S

someone

Yes, we know for certain that Mac, Windows, and Linux/UNIX all release
memory held by the process when they terminate. They also release
mutexes, close files, sockets, and such. What isn't clear is whether
your app leaves the files and shared resources in a consistent state
when you slam the process. Device drivers and video libraries were once
particularly fragile, but that is mostly just a bad rememberance these
days.

hmmm. I'm not sure I understand it yet... It's clear that they all
release memory + close files etc. At least static allocated memory is
surely released. What happens to memory/objects, allocated by "new" at
termination? We know that destructors to classes are not called. Is it a
memory leak or not? Is that a clear question? I hope there's a clear
answer...?
It can be that for some or even many apps, process cleanup by the OS is
sufficient. This should be a conscious choice, though, knowing what is
safe and what is not, rather than left to chance out of ignorance.
Destructors can do much more than simply release memory.

The largest problem in self-education is what you don't know about what
you need to know. It looks like you're coming to grips with process flow
on termination. You need to now understand more about what the OS thinks
of a process, its resources and lifetime. It's a long path, and aside
from my passing mention of destructors above, not language specific and
probably should be moved to a different newsgroup.

Not sure if we're talking about the same thing anymore... See my
question above.. Thank you!
 
G

Garrett Hartshaw

Maybe... Just think it's strange that no good/easy solutions exists, if
I understand this correctly...


I tried to do something like that.
Keyboard events: Yes, no problem.
Clicking "X" window: I think the OS forces a kill without being able to
capture anything...


So, like me you don't know if linux, windows or mac OS free's the memory
when exit(0) or exit(1) is called, and at least we don't count on it
unless somebody (in here?) says otherwise...


Hmm. Ok.

glut calls exit() when the X button is pressed.
in freeglut you can tell it to return from glutMainLoop instead, I
forget what you need to call. I personally wouldn't bother with
either of them, as I usually use straight glx (because its easier to
get a opengl 3 context), but you could have a look at have a look at
glfw.
 
G

Garrett Hartshaw

I just don't want static allocation, because only at runtime I know how
large arrays I need. So I'm saying I need dynamic allocation and I
cannot avoid that. Then std::vector<> and "new" both have the same
problem, with no cleaning up if there's an exit() somewhere.

As far as I can see, the solution is that I learn about smart pointers,
c++11 or std::tr1. And if that fails, I'll look at std::auto_ptr (though
not recommended from people in here)...

the smart pointers will do no better then std::vector if exit() is
called (which is why exit should be avoided). I think that your
problem could be solved by calling the destructors from atexit.

I would still recommend looking into smart pointers for the future.
 
S

someone

I downloaded glut and played with it a little. atexit will probably work
for you.

Wow... I think I just made something much (much?) better!

I really hope you and the other clever guys in here can comment on my
newly found solution below!
How do you find out?

I have some graphical objects and run some code, different from time to
time, showing different things. Based on what I want the program to
show, different geometries have to be drawn, requiring different vectors
of coordinates. I have some code that does a lot based on my input. It
then tells how large coordinate arrays I need. I then allocate that for
each geometry. Then I show that. ALSO: Better explanation: See below
---- bad explanation here, better below...
I didn't cut and paste this from working code.

Consider this,

struct SomeData {
std::vector<glVertex3f> points;
};

// global scope.
SomeData someData;

int main() {

// there are more efficient ways to do this.
// but maybe you should see how long this takes
// before you worry about it.
someData.points.push_back(glVertex3f(1.,2.,3.)); // or whatever.

Actually my data (coordinates) comes from a fortran program. I link it
with my c++ (a bit C'ish though) program. I pass a pointer to an array
of double's for all X + Y + Z-values. I looks like:

----- C++ Program ----
extern "C" {
void getCoords_(...... const int *maxVectorSize,
double *cpp_X, double *cpp_Y, double *cpp_Z, int *some_id);
}

bla.bla.
getCoords_( &someInteger, &someOtherInteger, &maxVectorSize,
cpp_X, cpp_Y, cpp_Z, some_id);

====== Fortran Program =====
blabla.

----- C++ Program ----
blabla.


So I don't have the point in a vertex3f, although I'm thinking that I
can probably do something better than here and only pass 1
glVertex-coordinate to Fortran...

As you can see: I pass a pointer to the array of double's (maybe I
should change the fortran-code so it outputs the results as float, which
is used by opengl)...
// more stuff here...
// and then...
glutMainLoop();
}

Now when glutMainLoop calls exit, someData will be destroyed, and along
with it the memory that points contains.

My problem is more complicated than that, but my solution is perfectly
close to the idea in your suggested solution... I'll show my suggestion
shortly...
I think std::vector is a little easier to deal with.

Maybe... I'm just a little bit stupid and afraid. So...

In my case: Using std::vector, would still allow me to pass a pointer to
arrays (of double or float) into a Fortran90 subroutine, which needs
pointers to the data so it can store the results... Is there any
problems here with std::vector???

What do you think?


======== here's my possible solution, please give some input ========
First: Short explanation... I have a class: drawableObj (base class)
from which all different geometries iherit.

As an example, I have a gear class that inherits from drawableObj.
Problem: Currently I only have a gear-class but later I want to have
other geometrical classes deriving from base class drawableObj, e.g.
maybe introduce a connecting "shaft"-class + a foundation + maybe sun +
stars + skyes + landscape etc. etc (all graphical objects derive from
base class drawableObj)...

I made it this way, because I wanted to introduce polymorphism in my
display()-function of my program... This makes it *REALLY* easy to
add/remove objects... See below... Enough introduction...


--- main.cpp ---
drawableObj allObjs; // must be global!

void display()
{
glClear(GL_COLOR_BUFFER_BIT);
...
// UPDATE ALL GRAPHICAL OBJS...
for (int z=0; z<(int) drawableObj::pObjs.size(); z++)
{
glPushMatrix();
((gearClass*) drawableObj::pObjs[z])->updateDisplay();
glPopMatrix();
}
..
glutSwapBuffers(); // also does glFlush();
}

int main(int argc, char** argv)
{
drawableObj *testGearPtr =
new gearClass( .... ); // rotSpeed etc, etc... bla.bla

drawableObj *testGearPtr2 =
new gearClass( .... ); // rotSpeed etc, etc... bla.bla

// Calculate INITIAL X+Y+Z points (only done once!)
for (int z=0; z<(int) drawableObj::pObjs.size(); z++)
{
((gearClass*) drawableObj::pObjs[z])->callFortran();
}

// ******* OpenGL starting... *******
glutInit(&argc, argv);
.... bla bla...

glutMainLoop(); // exits directly to OS from here...

return(0); // never comes here - just to satisfy compiler...
}





--- helper.h (#include guard not shown) ---
class drawableObj
{
// private: // protected: // I don't have anything here

public:
// global+static pointer to all GRAPHICAL objs:
static vector<drawableObj*> pObjs;

drawableObj(); // constructor

// destructor
virtual ~drawableObj();

// member functions
virtual void draw(); // <---used in openGL display loop
void showNumObjs();
void test();
};





--- gearClass.h (#include guard not shown) ---
class gearClass : public drawableObj
{
private:

public:
bool memAllocated; // IMPORTANT TO KNOW IF DELETE HAS BEEN CALLED
double *cpp_X, *cpp_Y, *cpp_Z;
bla bla...

virtual ~gearClass(); // destructor

// member functions
void deAllocate();
void callFortran();
void updateDisplay();
bla.bla
};





--- helper.cpp ---
#include "helper.h"
#include "gearClass.h" // for knowing "gearClass"-type

// NOT SURE ABOUT THIS, BUT COMPILER COMPLAINS IF NOT "EXTERN"...
extern vector<drawableObj*> drawableObj::pObjs;


drawableObj::~drawableObj() // destructor
{
int numObj = pObjs.size();
if (numObj == 0)
cout << " Destructing base (drawableObj), " <<
"no objects left: #objects: " <<
numObj << endl << endl;
else
{
cout << endl << "---- NB: BASE IS BEING DESTROYED, " <<
"BUT DERIVED OBJECTS MUST ALSO DIE ----" << endl;
int numObjs = (int) drawableObj::pObjs.size();
cout << "---- Number of obj's to delete: " << numObjs <<
" ----" << endl;
for (int z=0; z<numObjs; z++)
{
if ( ((gearClass*) drawableObj::pObjs[z])->memAllocated )
delete ((gearClass*) drawableObj::pObjs[z]);
}
}
}





--- gearClass.cpp ---
gearClass::gearClass() // constructor
{
drawableObj::pObjs.push_back((gearClass*) this); // ISN'T THIS NICE ??
... bla bla...

cpp_X = new double[maxVectorSize]; // NEEDS TO BE FREE'd BY DESTRUCTOR
cpp_Y = new double[maxVectorSize]; // NEEDS TO BE FREE'd BY DESTRUCTOR
cpp_Z = new double[maxVectorSize]; // NEEDS TO BE FREE'd BY DESTRUCTOR
memAllocated = true; // need to know if allocated or not...
}

gearClass::~gearClass() // destructor
{
if (memAllocated)
{
deAllocate();
drawableObj::pObjs.pop_back(); // REMOVE 1 COUNT...
cout << "Derived: gearClass::~gearClass() has free'd memory..." << endl;
memAllocated = false;
}
}

void gearClass::deAllocate()
{
cout << " (deallocating cpp_X, cpp_Y and cpp_Kontur_id)" << endl;
delete [] cpp_X;
delete [] cpp_Y;
delete [] cpp_Z;
}


======== that was possible solution, please give some input ========

Final remarks:

This code seem to clean up everything, by calling the destructors and
de-allocating correcty (because I have the global drawableObj allObjs in
top of main(), I think - isn't that right?)... Even if I use exit(0) or
exit(1), it cleans up, I think... Please tell me if I've made any error
somewhere, that I haven't seen... Also please write suggestions, if
something can be improved in ANY way!

Thank you, all! :)
 
S

someone

glut calls exit() when the X button is pressed.

Yep, thought so... In any case: I posted a possible solution elsewhere
(and changed the subject-line, because there are so many answers now).
Would be nice to hear your comments on my "possible solution"-subject
post...
in freeglut you can tell it to return from glutMainLoop instead, I
forget what you need to call. I personally wouldn't bother with either
of them, as I usually use straight glx (because its easier to get a
opengl 3 context), but you could have a look at have a look at glfw.

Ah, interesting... I'm interested in doing everything crossplatform
Windows/Linux. Learning/looking at glfw is on my "to-do list...", thanks
a lot for the hints (just need some more time to learn all that I want
to/would like to know)... :)
 
S

someone

the smart pointers will do no better then std::vector if exit() is
called (which is why exit should be avoided). I think that your problem
could be solved by calling the destructors from atexit.

I would still recommend looking into smart pointers for the future.

Great Garret - thanks, agreed I'll look into it and learn the idea
behind using it...

Also: Please comment on my other reply ( with subject line: Re: noob
question - destructors - freeing memory... POSSIBLE SOLUTION FOUND? )

I'm very interested in hearing what people has to say about that :)
 
G

Garrett Hartshaw

Re: noob question - destructors - freeing memory... POSSIBLE SOLUTION
FOUND?


I downloaded glut and played with it a little. atexit will probably work
for you.

Wow... I think I just made something much (much?) better!

I really hope you and the other clever guys in here can comment on my
newly found solution below!
How do you find out?

I have some graphical objects and run some code, different from time to
time, showing different things. Based on what I want the program to
show, different geometries have to be drawn, requiring different vectors
of coordinates. I have some code that does a lot based on my input. It
then tells how large coordinate arrays I need. I then allocate that for
each geometry. Then I show that. ALSO: Better explanation: See below
---- bad explanation here, better below...
I didn't cut and paste this from working code.

Consider this,

struct SomeData {
std::vector<glVertex3f> points;
};

// global scope.
SomeData someData;

int main() {

// there are more efficient ways to do this.
// but maybe you should see how long this takes
// before you worry about it.
someData.points.push_back(glVertex3f(1.,2.,3.)); // or
whatever.


Actually my data (coordinates) comes from a fortran program. I link it
with my c++ (a bit C'ish though) program. I pass a pointer to an array
of double's for all X + Y + Z-values. I looks like:

----- C++ Program ----
extern "C" {
void getCoords_(...... const int *maxVectorSize,
double *cpp_X, double *cpp_Y, double *cpp_Z, int *some_id);
}

bla.bla.
getCoords_( &someInteger, &someOtherInteger, &maxVectorSize,
cpp_X, cpp_Y, cpp_Z, some_id);

====== Fortran Program =====
blabla.

----- C++ Program ----
blabla.



So I don't have the point in a vertex3f, although I'm thinking that I
can probably do something better than here and only pass 1
glVertex-coordinate to Fortran...

As you can see: I pass a pointer to the array of double's (maybe I
should change the fortran-code so it outputs the results as float, which
is used by opengl)...
// more stuff here...
// and then...
glutMainLoop();
}

Now when glutMainLoop calls exit, someData will be destroyed, and along
with it the memory that points contains.

My problem is more complicated than that, but my solution is perfectly
close to the idea in your suggested solution... I'll show my suggestion
shortly...

I think std::vector is a little easier to deal with.

Maybe... I'm just a little bit stupid and afraid. So...

In my case: Using std::vector, would still allow me to pass a pointer to
arrays (of double or float) into a Fortran90 subroutine, which needs
pointers to the data so it can store the results... Is there any
problems here with std::vector???

What do you think?



======== here's my possible solution, please give some input ========
First: Short explanation... I have a class: drawableObj (base class)
from which all different geometries iherit.

As an example, I have a gear class that inherits from drawableObj.
Problem: Currently I only have a gear-class but later I want to have
other geometrical classes deriving from base class drawableObj, e.g.
maybe introduce a connecting "shaft"-class + a foundation + maybe sun +
stars + skyes + landscape etc. etc (all graphical objects derive from
base class drawableObj)...

I made it this way, because I wanted to introduce polymorphism in my
display()-function of my program... This makes it *REALLY* easy to
add/remove objects... See below... Enough introduction...



--- main.cpp ---
drawableObj allObjs; // must be global!

void display()
{
glClear(GL_COLOR_BUFFER_BIT);
...
// UPDATE ALL GRAPHICAL OBJS...
for (int z=0; z<(int) drawableObj::pObjs.size(); z++)
{
glPushMatrix();
((gearClass*) drawableObj::pObjs[z])->updateDisplay();
glPopMatrix();
}
..
glutSwapBuffers(); // also does glFlush();
}

int main(int argc, char** argv)
{
drawableObj *testGearPtr =
new gearClass( .... ); // rotSpeed etc, etc... bla.bla

drawableObj *testGearPtr2 =
new gearClass( .... ); // rotSpeed etc, etc... bla.bla

// Calculate INITIAL X+Y+Z points (only done once!)
for (int z=0; z<(int) drawableObj::pObjs.size(); z++)
{
((gearClass*) drawableObj::pObjs[z])->callFortran();
}

// ******* OpenGL starting... *******
glutInit(&argc, argv);
.... bla bla...

glutMainLoop(); // exits directly to OS from here...

return(0); // never comes here - just to satisfy compiler...
}









--- helper.h (#include guard not shown) ---
class drawableObj
{
// private: // protected: // I don't have anything here

public:
// global+static pointer to all GRAPHICAL objs:
static vector<drawableObj*> pObjs;

drawableObj(); // constructor

// destructor
virtual ~drawableObj();

// member functions
virtual void draw(); // <---used in openGL display loop
void showNumObjs();
void test();
};









--- gearClass.h (#include guard not shown) ---
class gearClass : public drawableObj
{
private:

public:
bool memAllocated; // IMPORTANT TO KNOW IF DELETE HAS BEEN CALLED
double *cpp_X, *cpp_Y, *cpp_Z;
bla bla...

virtual ~gearClass(); // destructor

// member functions
void deAllocate();
void callFortran();
void updateDisplay();
bla.bla
};









--- helper.cpp ---
#include "helper.h"
#include "gearClass.h" // for knowing "gearClass"-type

// NOT SURE ABOUT THIS, BUT COMPILER COMPLAINS IF NOT "EXTERN"...
extern vector<drawableObj*> drawableObj::pObjs;



drawableObj::~drawableObj() // destructor
{
int numObj = pObjs.size();
if (numObj == 0)
cout << " Destructing base (drawableObj), " <<
"no objects left: #objects: " <<
numObj << endl << endl;
else
{
cout << endl << "---- NB: BASE IS BEING DESTROYED, " <<
"BUT DERIVED OBJECTS MUST ALSO DIE ----" << endl;
int numObjs = (int) drawableObj::pObjs.size();
cout << "---- Number of obj's to delete: " << numObjs <<
" ----" << endl;
for (int z=0; z<numObjs; z++)
{
if ( ((gearClass*) drawableObj::pObjs[z])->memAllocated )
delete ((gearClass*) drawableObj::pObjs[z]);
}
}
}









--- gearClass.cpp ---
gearClass::gearClass() // constructor
{
drawableObj::pObjs.push_back((gearClass*) this); // ISN'T THIS NICE ??
... bla bla...

cpp_X = new double[maxVectorSize]; // NEEDS TO BE FREE'd BY DESTRUCTOR
cpp_Y = new double[maxVectorSize]; // NEEDS TO BE FREE'd BY DESTRUCTOR
cpp_Z = new double[maxVectorSize]; // NEEDS TO BE FREE'd BY DESTRUCTOR
memAllocated = true; // need to know if allocated or not...
}

gearClass::~gearClass() // destructor
{
if (memAllocated)
{
deAllocate();
drawableObj::pObjs.pop_back(); // REMOVE 1 COUNT...
cout << "Derived: gearClass::~gearClass() has free'd memory..." << endl;
memAllocated = false;
}
}

void gearClass::deAllocate()
{
cout << " (deallocating cpp_X, cpp_Y and cpp_Kontur_id)" << endl;
delete [] cpp_X;
delete [] cpp_Y;
delete [] cpp_Z;
}



======== that was possible solution, please give some input ========

Final remarks:

This code seem to clean up everything, by calling the destructors and
de-allocating correcty (because I have the global drawableObj allObjs in
top of main(), I think - isn't that right?)... Even if I use exit(0) or
exit(1), it cleans up, I think... Please tell me if I've made any error
somewhere, that I haven't seen... Also please write suggestions, if
something can be improved in ANY way!

Thank you, all! :)

If you make cpp_X, etc. std::vector<double> instead of double * you
can get rid of your deAllocate function. just replace the 'new
double[size]' with 'vector<double>( size )' in you constructor, and
use '&vec[0]' instead of 'vec' to pass to a function requiring the
data as a double *. Otherwise I think that it should work (I think
the destructors of static functions are registered with atexit behind
the scenes, but I am not positive. You woul.d need to register the
destructors manually with atexit if this is not the case.)
 
J

Juha Nieminen

someone said:
I just don't want static allocation, because only at runtime I know how
large arrays I need.

I still don't see the connection with base and derived classes in your
original post.
 
J

Jorgen Grahn

my earlier post was incorrect. exit() does not invoke any destructors.
idiot nick...

Still, the right approach that isn't to try to make your program play
nice with exit() randomly sprinkled in the code: the right approach is
to eliminate those exit()s.

It's typically trivial to find them by looking at the symbol tables in
the object code.

/Jorgen
 
S

Stefan Ensslen

hmmm. I'm not sure I understand it yet... It's clear that they all
release memory + close files etc. At least static allocated memory is
surely released.


The distinction between "static allocated memory" and dynamically
allocated memory only exists within the scope of the programming
language. Operating Systems make a distinction between heap and stack
memory. In most cases "static memory" will be located on the stack and
dynamic memory on the heap, but that is up to the implementation of
the compiler.

What is guaranteed by the OS is that both stack and heap memory will
be released upon process termination. Even more, Windows guarantees
that memory in its numerous sub-systems like GDI and COM will be
released.

What happens to memory/objects, allocated by "new" at
termination? We know that destructors to classes are not called.
Is it a memory leak or not?

Destructors and memory management are pretty tightly coupled (new "="
constructor, delete "=" destructor), but there are (corner) cases with
placement new where destructors will be explicitely called without a
matching "delete". This would still count as a memory leak.


Is that a clear question? I hope there's a clear
answer...?

At least it is a clear question.

We had lots of discussion about whether an allocation with "new" still
counts as a memory leak when the programmer intentionally left out the
matching "delete" because the OS will re-claim the memory anyway. I
tend to say that this should not be considered a memory leak, even if
this makes the definition of a memory leak a bit harder.

Regards,
Stuart
 
S

someone

The distinction between "static allocated memory" and dynamically
allocated memory only exists within the scope of the programming
language. Operating Systems make a distinction between heap and stack
memory. In most cases "static memory" will be located on the stack and
dynamic memory on the heap, but that is up to the implementation of
the compiler.

What is guaranteed by the OS is that both stack and heap memory will
be released upon process termination. Even more, Windows guarantees
that memory in its numerous sub-systems like GDI and COM will be
released.

But not linux/mac os X, meaning in this area Windows is more "safe" ?
Destructors and memory management are pretty tightly coupled (new "="
constructor, delete "=" destructor), but there are (corner) cases with
placement new where destructors will be explicitely called without a
matching "delete". This would still count as a memory leak.
Ok.

Is that a clear question? I hope there's a clear

At least it is a clear question.

We had lots of discussion about whether an allocation with "new" still
counts as a memory leak when the programmer intentionally left out the
matching "delete" because the OS will re-claim the memory anyway. I
tend to say that this should not be considered a memory leak, even if
this makes the definition of a memory leak a bit harder.

Ok, thank you very much - I think I understand now.
 
S

someone

Still, the right approach that isn't to try to make your program play
nice with exit() randomly sprinkled in the code: the right approach is
to eliminate those exit()s.

With exceptions (try/catch), I guess...
It's typically trivial to find them by looking at the symbol tables in
the object code.

Uh, sounds very interesting. I googled a bit - it's something to do with
the tool "nm" in linux, isn't it?

Here's "nm" on my main-file:

nm main.o0000000000000000 R Pi
000000000000092b t _GLOBAL__sub_I_Pi
U _Unwind_Resume
U _Z10screenshotPKcii
U _Z11makeLineSepv
00000000000008ca t _Z41__static_initialization_and_destruction_0ii
00000000000003b7 T _Z5timeri
00000000000000b5 T _Z7displayv
U _Z7findboxv
0000000000000176 T _Z7reshapeii
0000000000000000 T _Z7specialiii
000000000000034f T _Z8keyboardhii
0000000000000044 b _ZL4xPos
0000000000000048 b _ZL4yPos
U _ZN11drawableObj5pObjsE
U _ZN11drawableObjC1Ev
U _ZN11drawableObjD1Ev
U _ZN9gearClass11callFortranEv
U _ZN9gearClass13updateDisplayEv
U _ZN9gearClassC1E9gearTypesdiddddddddffd
0000000000000000 W _ZNKSt6vectorIP11drawableObjSaIS1_EE4sizeEv
U _ZNSolsEPFRSoS_E
U _ZNSolsEd
U _ZNSolsEm
0000000000000000 W _ZNSt6vectorIP11drawableObjSaIS1_EEixEm
U _ZNSt8ios_base4InitC1Ev
U _ZNSt8ios_base4InitD1Ev
U _ZSt4cout
U
_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
0000000000000040 b _ZStL8__ioinit
U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
U _ZdlPv
U _Znwm
U __cxa_atexit
U __dso_handle
U __gxx_personality_v0
0000000000000020 B allObjs
U exit
U glClear
U glEnable
U glLoadIdentity
U glMatrixMode
U glPopMatrix
U glPushMatrix
U glShadeModel
U glTranslatef
U glViewport
U gluOrtho2D
U glutCreateWindow
U glutDisplayFunc
U glutInit
U glutInitDisplayMode
U glutInitWindowSize
U glutKeyboardFunc
U glutMainLoop
U glutPostRedisplay
U glutReshapeFunc
U glutSpecialFunc
U glutSwapBuffers
U glutTimerFunc
00000000000003dd T main
0000000000000010 B makeScreenshot
0000000000000000 D onlyWhiteGear
0000000000000008 B screenLimits
0000000000000000 B stopRotation
0000000000000004 D winSizeX
0000000000000008 D winSizeY


What's those hex-numbers?
 
S

someone

On 01/02/2012 03:11 AM, LR wrote:
exit(1), it cleans up, I think... Please tell me if I've made any error
somewhere, that I haven't seen... Also please write suggestions, if
something can be improved in ANY way!

Thank you, all! :)

If you make cpp_X, etc. std::vector<double> instead of double * you can
get rid of your deAllocate function. just replace the 'new double[size]'
with 'vector<double>( size )' in you constructor, and use '&vec[0]'
instead of 'vec' to pass to a function requiring the data as a double *.

Ok, roger I'll try that a bit later (in a few hours) and get back if any
problems/questions arise, thanks (the calling Fortran part made me think
that it wouldn't work, but I guess you're probably right and that I have
to see for myself :) )!
Otherwise I think that it should work (I think the destructors of static
functions are registered with atexit behind the scenes, but I am not
positive. You woul.d need to register the destructors manually with
atexit if this is not the case.)

Ok, got it. Thank you very much - am a bit tired now, but will try it in
a few hours :)
 
S

someone

Ok, it has that to do with derived classes and virtual destructors, that
I use derived classes and virtual destructors in a bigger program. I
then found out that (at least not all) my destructors where called (in
the bigger program) and then I sought a solution I could implement in my
opengl-program - to do that, I posted a minimal example...

I also posted a longer code sequence with slightly modified subject like...
I still don't see the connection with base and derived classes in your
original post.

Sorry, I'm not sure I understand it then... The original post had many
similarities with my working code... The similarities are/is the
connection... Do I misunderstand ?
 
D

Dombo

Op 02-Jan-12 17:40, someone schreef:
But not linux/mac os X, meaning in this area Windows is more "safe" ?

Neither Linux nor Mac OSX have GDI and COM. The bottom line is that
those operating systems will release resources claimed on behalf of the
process when the process ceases to exist, regardless of whether the
process releases those resources itself or not.
 
L

LR

someone said:
Maybe... I'm just a little bit stupid and afraid. So...

Try it.


--- main.cpp ---
drawableObj allObjs; // must be global!
int main(int argc, char** argv)
{
drawableObj *testGearPtr =
new gearClass( .... ); // rotSpeed etc, etc... bla.bla

drawableObj *testGearPtr2 =
new gearClass( .... ); // rotSpeed etc, etc... bla.bla

If you have a global allObjs, how do these pointers make their way into
that object?

// ******* OpenGL starting... *******
glutInit(&argc, argv);
.... bla bla...

glutMainLoop(); // exits directly to OS from here...

return(0); // never comes here - just to satisfy compiler...

Odd, because it shouldn't be required at all.
class drawableObj
{
// private: // protected: // I don't have anything here

public:
// global+static pointer to all GRAPHICAL objs:
static vector<drawableObj*> pObjs;

Why is this static? Why not just make it a member class?
drawableObj(); // constructor

// destructor
virtual ~drawableObj();

// member functions
virtual void draw(); // <---used in openGL display loop
void showNumObjs();
void test();
};
class gearClass : public drawableObj
Ok, now I'm confused. Is drawableObj some sort of polymorphic base
class, or is it a container for a whole bunch of objects.
{
private:

public:
bool memAllocated; // IMPORTANT TO KNOW IF DELETE HAS BEEN CALLED
Use std::vector and this problem doesn't arise.
#include "gearClass.h" // for knowing "gearClass"-type

// NOT SURE ABOUT THIS, BUT COMPILER COMPLAINS IF NOT "EXTERN"...
extern vector<drawableObj*> drawableObj::pObjs;

Coupling your class with an external object made elsewhere probably
limits the utility of the class.
drawableObj::~drawableObj() // destructor
if ( ((gearClass*) drawableObj::pObjs[z])->memAllocated )
delete ((gearClass*) drawableObj::pObjs[z]);
Or use a shared pointer and avoid this.
--- gearClass.cpp ---
gearClass::gearClass() // constructor
{
drawableObj::pObjs.push_back((gearClass*) this); // ISN'T THIS NICE ??
... bla bla...

No. I don't think so. Using a global like this seems like a bad idea.
I think it's better to decouple things.


======== that was possible solution, please give some input ========

Final remarks:

I snipped a lot and just hit a few points. I think what you're doing is
asking for trouble.

FWIW, here's my suggestion. Most of it is just trace so you can see
what's going on. I consider this to be a snippet. For example, it would
be a better idea to put the classes and implementations in header and
source files.

You might want to try creating a new project, copying the code, and
seeing what happens.

-----------------------
#include <iostream>
#include <string>
#include <vector>
#include <memory>



class DrawObjectBase {
public:
DrawObjectBase() {
std::cout << "DrawObjectBase(" << this << ")" << std::endl;
}
virtual ~DrawObjectBase() {
std::cout << "~DrawObjectBase(" << this << ")" << std::endl;
}
virtual void draw(const std::string &someParameter) const {
std::cout
<< "DrawObjectBase::draw("
<< this
<< ","
<< someParameter
<< ")"
<< std::endl;
}
};

class Star : public DrawObjectBase {
public:
Star()
:
DrawObjectBase()
{
std::cout << "Star(" << this << ")" << std::endl;
}
~Star() {
std::cout << "~Star(" << this << ")" << std::endl;
}
void draw(const std::string &s) const {
std::cout << "Star::draw(" << this << "," << s << ")" << std::endl;
}
};

class Planet : public DrawObjectBase {
public:
Planet()
:
DrawObjectBase()
{
std::cout << "Planet(" << this << ")" << std::endl;
}
~Planet() {
std::cout << "~Planet(" << this << ")" << std::endl;
}
void draw(const std::string &s) const {
std::cout
<< "Planet::draw(" << this << "," << s << ")" << std::endl;
}
};

class DrawObjects {
// this isn't the best way to do this,
// just an example.
// a point of departure, not a destination.
public:
// maybe these typedefs should be classes on their own
typedef
std::tr1::shared_ptr<DrawObjectBase> DrawObjectBaseContainer;
typedef std::vector<DrawObjectBaseContainer> DrawObjectsContainer;
DrawObjectsContainer objects; // public isn't great here...
public:
DrawObjects() : objects() {} // or howver many you need.
void add(const DrawObjectBaseContainer &d) {
objects.push_back(DrawObjectBaseContainer(d));
}
void draw(const std::string &someParameter) const {
for(DrawObjectsContainer::const_iterator
i=objects.begin();
i!=objects.end();
i++) {
i->get()->draw(someParameter);
}
}
};

DrawObjects ourGlobalObjects;

void f() {

ourGlobalObjects
.add(DrawObjects::DrawObjectBaseContainer(new Star()));
ourGlobalObjects
.add(DrawObjects::DrawObjectBaseContainer(new Planet()));
ourGlobalObjects
.add(DrawObjects::DrawObjectBaseContainer(new Planet()));

ourGlobalObjects.draw("Draw Once");
ourGlobalObjects.draw("Draw Again");
}

int main() {
f();
exit(0); // because....
}




-------------------------------------------

And the output is,

DrawObjectBase(00345768)
Star(00345768)
DrawObjectBase(003468B8)
Planet(003468B8)
DrawObjectBase(00346880)
Planet(00346880)
Star::draw(00345768,Draw Once)
Planet::draw(003468B8,Draw Once)
Planet::draw(00346880,Draw Once)
Star::draw(00345768,Draw Again)
Planet::draw(003468B8,Draw Again)
Planet::draw(00346880,Draw Again)
~Star(00345768)
~DrawObjectBase(00345768)
~Planet(003468B8)
~DrawObjectBase(003468B8)
~Planet(00346880)
~DrawObjectBase(00346880)
----------------------------------
 
J

Jorgen Grahn

With exceptions (try/catch), I guess...

I don't follow you. Exceptions and exit() don't have much in common.
Uh, sounds very interesting. I googled a bit - it's something to do with
the tool "nm" in linux, isn't it?

Yes, that's the way I'd do it on that platform.
Here's "nm" on my main-file:

nm main.o0000000000000000 R Pi
000000000000092b t _GLOBAL__sub_I_Pi
U _Unwind_Resume
U _Z10screenshotPKcii
U _Z11makeLineSepv ....
U exit ....

What's those hex-numbers?

I don't know exactly, but you can think of them as the address of the
function (or data) within that particular file. 'exit' is (U)ndefined
because it's something referenced from, not defined in, the file; thus
it has no address.

You should check if your nm accepts a -C option, by the way. It makes
C++ function names readable.

/Jorgen
 
S

someone

Neither Linux nor Mac OSX have GDI and COM. The bottom line is that
those operating systems will release resources claimed on behalf of the
process when the process ceases to exist, regardless of whether the
process releases those resources itself or not.

Ok, thanks.
 
S

someone

Thank you, all! :)

If you make cpp_X, etc. std::vector<double> instead of double * you can
get rid of your deAllocate function. just replace the 'new double[size]'
with 'vector<double>( size )' in you constructor, and use '&vec[0]'
instead of 'vec' to pass to a function requiring the data as a double *.

Ok... Now I did it... However, I'm not sure there's any difference at
all... I mean: Now I have:

--- header file ---
std::vector<double> cpp_X, cpp_Y, cpp_Z;

--- c++ file ---
cpp_X.resize( maxVectorSize ); // new double[maxVectorSize];
cpp_Y.resize( maxVectorSize ); // new double[maxVectorSize];
cpp_Z.resize( maxVectorSize ); // new double[maxVectorSize];

I modified my deAllocate slightly:
void gearClass::deAllocate()
{
cpp_X.clear();
cpp_Y.clear();
cpp_Z.clear();
cout << " (deallocating)" << endl;
}

However: How can I convince myself that deAllocate is un-neccessary in
either case, using either std::vector for cpp_X, cpp_Y and cpp_Z ?

In my naive opionion, using std::vector makes no difference at all... In
all cases, I actually think the deAllocate() function is not strictly
necessary because the OS would cleanup in either case. However, I'm
happy I did it - 2 reasons:

1) Better to clean up in any cases - just better programming practice, I
think.
2) Using std::vector is more "the C++-way" compared to the usual
"C-methods" that I tend to use, because I'm maybe slightly more familiar
with C than C++ (however, my skills are improving now).
Otherwise I think that it should work (I think the destructors of static
functions are registered with atexit behind the scenes, but I am not
positive. You woul.d need to register the destructors manually with
atexit if this is not the case.)

You mean the destructors for std::vector, right?

How do I know whether or not destructors for std::vector has/is been
called with my current code (based on your suggestion) ?

With my own destructors, it wasn't that complicated to add some
cout-statements, as I could program the destructor myself. This is
however, not the case for std::vector destructors - I don't know how
these destructors look like at all...
 
G

Garrett Hartshaw

Re: noob question - destructors - freeing memory... POSSIBLE SOLUTION
FOUND?


Thank you, all! :)

If you make cpp_X, etc. std::vector<double> instead of double * you can
get rid of your deAllocate function. just replace the 'new double[size]'
with 'vector<double>( size )' in you constructor, and use '&vec[0]'
instead of 'vec' to pass to a function requiring the data as a
double *.

Ok... Now I did it... However, I'm not sure there's any difference at
all... I mean: Now I have:

--- header file ---
std::vector<double> cpp_X, cpp_Y, cpp_Z;

--- c++ file ---
cpp_X.resize( maxVectorSize ); // new double[maxVectorSize];
cpp_Y.resize( maxVectorSize ); // new double[maxVectorSize];
cpp_Z.resize( maxVectorSize ); // new double[maxVectorSize];

I modified my deAllocate slightly:
void gearClass::deAllocate()
{
cpp_X.clear();
cpp_Y.clear();
cpp_Z.clear();
cout << " (deallocating)" << endl;
}

However: How can I convince myself that deAllocate is un-neccessary in
either case, using either std::vector for cpp_X, cpp_Y and cpp_Z ?

In my naive opionion, using std::vector makes no difference at all... In
all cases, I actually think the deAllocate() function is not strictly
necessary because the OS would cleanup in either case. However, I'm
happy I did it - 2 reasons:

yes, if you don't use push_back, etc... the std::vector is pretty
much the same (except for the need to call delete).
1) Better to clean up in any cases - just better programming practice, I
think.
2) Using std::vector is more "the C++-way" compared to the usual
"C-methods" that I tend to use, because I'm maybe slightly more familiar
with C than C++ (however, my skills are improving now).


You mean the destructors for std::vector, right?

How do I know whether or not destructors for std::vector has/is been
called with my current code (based on your suggestion) ?

With my own destructors, it wasn't that complicated to add some
cout-statements, as I could program the destructor myself. This is
however, not the case for std::vector destructors - I don't know how
these destructors look like at all...

If the destructor for a class is called, the destructors of it's
members will be destroyed as well, so if ~gearClass is called, the
vectors destructors will be called.

If the only place you call deAllocate is in your destructor, there is
no need to call clear(), as this is handled by the std::vector
destructor.

Finally, in your constructor, you can use the std::vector(
std::size_t n, T = T(), Allocator = Allocator() ) constructor to
create the vector with the correct size, rather then using the
default constructor and then calling resize().

eg. instead of

gearClass()
{
cpp_X.resize( size );
cpp_Y.resize( size );
cpp_Z.resize( size );
}

use

gearClass()
: cpp_X( size ), cpp_Y( size ), cpp_Z( size )
{}
 

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,754
Messages
2,569,521
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top