=?ISO-8859-15?Q?Re:_noob_question_-_destructors_-_free?= =?ISO-8859-15?Q?ing_memory..._POSSIBLE_SOLUTION=0A_FOUND=3F?=
On Mon, 02 Jan 2012 05:23:01 +0100, someone <newsboost@gmail.com>
wrote:
On 01/02/2012 03:11 AM, LR wrote:
someone wrote:
On 01/01/2012 10:03 AM, Juha Nieminen wrote:
someone<newsboost@gmail.com> wrote:
I don't think I can avoid it... I have some 20.000 points that
needs
real fast access to screen buffer in opengl application...
What exactly does this have to do with derived classes and
virtual
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!
I just don't want static allocation, because only at runtime I
know how
large arrays I need.
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...
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.
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.)