is bad to use new/delete for huge class?

Started by
48 comments, last by synth_cat 17 years, 9 months ago
Quote:Original post by synth_cat
Well, thanks for that explanation, deathkrush!

So, I'm curious: If I were to only use resize() to create this array, without any of the dynamic stuff ever being used, what would be the exact advantages over just saying "TRI tris[TRIS_SIZE]?" I ask this because I do not intend to resize my arrays during execution; there are various design reasons why this would be problematic.


vectors store their data on the heap, not on the stack, so you no longer have those arrays taking up space in that precious ~1MB stack space.

Quote:
Is the syntax for accessing a data element of a vector the same as for an array? For example, would this work?
*** Source Snippet Removed ***


Yes.

Also note that you can use vector<TRI> tris(TRI_SIZE); to get the same effect as the first 2 lines.

Quote:
I know I keep asking this question, but can someone tell me at what point it becomes requisite to use these special array-creation methods? Or should I just use vectors for all the arrays I ever make, just to be safe?


I use vectors / other std::containers for just about every array related thing I need to do. I use std::string for all string operations where I can.

Its easier because I dont have to worry about creating, naming and updating "magic" numbers for array sizes. In most stl implementations std::vector will do bounds checking in debug mode which can also be a help.

I think zahlman put it best one time, something like "arrays make sense when the size of the array comes from the program domain ( developing a chess game, the chessboard is *always* 8 x 8 )".
Advertisement
Quote:Original post by rip-off
vectors store their data on the heap, not on the stack, so you no longer have those arrays taking up space in that precious ~1MB stack space.


And at the same time, do the work of "storing stuff on the heap" *for* you, so you can treat it *as if* it were on the stack when you are writing your code.

Quote:I think zahlman put it best one time, something like "arrays make sense when the size of the array comes from the program domain ( developing a chess game, the chessboard is *always* 8 x 8 )".


Indeed. I'd be *very* interested to hear where the numbers 40000 points, 3000 of which are for triangles (thus 1000 triangles) come from. Aren't you reading these values from a file? Shouldn't it be the amount of stuff described in the file which dictates these values? These numbers smell quite strongly of artificial limits.

Another huge red flag to the given approach (going hand in hand with another vector advantage) is the pairing of arrays with "current" index values. I can envision loading code where values are iteratively assigned to the current index and then said index is post-incremented, such that it's really a count of the total used items. A std::vector automatically tracks the number of stored things, and strongly "binds" the count to the array storage by virtue of them being in the same object instance. This way, you can't possibly mess up updating the count (except by corrupting memory belonging to the vector object - C++ may offer lots of type-safety but it's still quite memory-unsafe by design).

The other things you should be looking at doing:

- Bundle x/y and x/y/z groupings into structs, and other related groupings into structs and/or classes (possible aggregating x/y and/or x/y/z members).

- Separate out the functions, assigning them to the appropriate sub-structures identified in the previous step in a logical manner. You might need to take a *big* step back and re-think your design from the beginning.
A good way to solve almost any problem in an object oriented language is to create create more types (classes).
--AnkhSVN - A Visual Studio .NET Addin for the Subversion version control system.[Project site] [IRC channel] [Blog]
Well, I finally braced myself and did it. Today and yesterday I completely hacked apart the modeller and put it back together in three classes instead of one. Of course, I'm not completely satisfied with the job, because there's a lot of passing around of pointers to classes between themselves, and the feeling isn't completely modular, but it's probably the best I'll ever be able to break this down to (it is a modeller, after all.)

Quote:
These numbers smell quite strongly of artificial limits.

Yep - I felt the same way from the start. However, I think I will keep things this way because all the elements in tris[] contain indeces to elements in pnts[], and that could possibly break down if, for example, the pnts[] array were to suddenly change size.

One more question about std::vector: does it have any disadvantages as compared to static arrays? Is it slower? If not, it sounds like a very nice tool...

Thanks!
Greg Philbrick, Game Developercoming soon . . . Overhauled CellZenith
I have a sort of emergency here, if anyone can help:

I just turned my big arrays into vectors like you guys told me too. The whole tihng compiled OK, but when I tried to debug-run it, it failed. I got a pop-up warning that reads like this:

Debug Assertion Failed!
Expression: vector subscript out of range.

Can someone please tell me what that means? Do even vectors have a size limit which I somehow managed to break with MAX_POINTS? Could it have been my ZeroMemory() calls which did this (I don't know if it's legal to zero a vector this way or not)...? These ZeroMemory calls look like this, for reference
ZeroMemory(&tris,sizeof(tris));


Thanks again!
Greg Philbrick, Game Developercoming soon . . . Overhauled CellZenith
If tris is the name of your vector, calling ZeroMemory() on it like that is extremely not kosher. A vector of primitive type starts with all zero elements by default, with other types it calls the default constructor. If you want to fill the vector with all elements of a specific value when creating it, you can do so in the constructor call.
Well, I removed all the ZeroMemory() calls on the vectors, and the program at least ran without a "Debug Assertion Failed!" warning.

However, my geometry became invisible. It seems as if all the data within std::vector<TRI> pnts and std::vector<POINT> pnts remains zero, even though both are passed through an InitWorld() function which is meant to define a grid of triangles and points. InitWorld() works fine when tris and pnts are defined as static arrays, but no when they are vectors.

So I need to ask again - is there _any_ difference at all in assigning data to vectors than there is in assigning data to arrays?

Let's say I have a struct like this:
struct TRI{   int pnt_idx1;   int pnt_idx2;   int pnt_idx3;};

and a vector like this (a member of a class and resized to MAX_TRIS in class constructor):
std::vector<TRI> tris;


Can someone please show me a snippet that takes tris and assigns element MAX_TRIS-1 to index values of, let's say, 1, 2, and 3?

Is it possible that InitWorld() didn't work because tris was filled through a class pointer? Example: tris is a member of a class called GeometryHandler and we have a GeometryHandler* pointer called ghandler_pnt. An assignment to tris would have looked like this:
ghandler_pnt->tris[x].pnt_idx1=200;

Is there something wrong with this method of writing to a vector which could be the reason that all my std::vector<TRI> tris data seems to stay zero?

Thanks!
Greg Philbrick, Game Developercoming soon . . . Overhauled CellZenith
Can you post InitWorld()?
Quote:Original post by synth_cat
Quote:
These numbers smell quite strongly of artificial limits.

Yep - I felt the same way from the start. However, I think I will keep things this way because all the elements in tris[] contain indeces to elements in pnts[], and that could possibly break down if, for example, the pnts[] array were to suddenly change size.


As long as it stores *indices* and not pointers, it will not. When a vector resizes, whatever was element 1 before is still element 1. Any more complicated manipulation of handles that might break in a vector will also break in an array - at least, everything I can think of, anyway.

Quote:One more question about std::vector: does it have any disadvantages as compared to static arrays? Is it slower? If not, it sounds like a very nice tool...


The only real cost is in terms of memory overhead (on a *typical* implementation *on average*, about 1/3 again as much memory as a static-array approach IF that static array were completely filled all the time).

Quote:Can someone please tell me what that means? Do even vectors have a size limit which I somehow managed to break with MAX_POINTS? Could it have been my ZeroMemory() calls which did this (I don't know if it's legal to zero a vector this way or not)...? These ZeroMemory calls look like this, for reference


AAARGH.

Please promise me you will forget you ever heard about the existence of a function called ZeroMemory, and never attempt to use it in C++ ever again.

Instead, use std::fill to "blank out" arrays, sequential containers and primitives. To "reset" objects, you should either assign a default-constructed object over top, or call an appropriate member function.

Also, note that you can pre-emptively resize vectors, although you shouldn't normally have to. Also note that you don't need to do any kind of zeroing out when you first create the vector.



I am going to try to be psychic: the reason you aren't properly filling the vectors in InitWorld is that you pass them by value. Because vectors are *real objects*, they are copied when passed to a function, and the copy gets populated and then thrown away. When you were using an array, you just passed the array name, which means you passed a pointer to the array storage. Writing stuff through the array pointer modified the actual array.

You can instead pass the vector by reference. However, depending on what exactly you are doing, this may not be the best solution.

Please post (or PM/email me or something :s) as much code as you're comfortable with; I have some free time this weekend ^^;
Here is InitWorld(), which is a method of a controller class called MapMaker (I'm much more C++-oriented than I was a few days ago :) )

MapMaker::InitWorld() takes an MM_Geometry object (an object which contains the std::vector<TRI> tris and std:: vector<POINT> pnts) and fills it. The important thing to remember here is that when MM_Geometry::tri and MM_Geometry::pnt are static arrays, this works fine, but when they are vectors, something goes wrong and I get nothing on my screen when my MM_Geometry data gets sent to my drawing function, which I _assume_ means that tris and pnts remain all zeroed out.

If it makes any difference, the MM_Geometry object that I use is local to WinMain() and is created and destroyed with "new" and "delete". The MapMaker object I use is identically located and created.

Anyway, here's the code:

//here are the structs, for referencestruct TRI{     bool alive;     int p[3];     float uv[3][2];};struct POINT{     bool alive;     D3DXVECTOR3 p;};


//and here is the class containing the vectorsclass MM_Geometry{	std::vector<TRI> tris;	std::vector<SYNTH_POINT> pnts;}//here is the constructor for the class:MM_Geometry::MM_Geometry(){    tris.resize(TRIS_SIZE);    pnts.resize(POINTS_SIZE);    }


void MapMaker::InitWorld(MM_Geometry* mm_geo, int width, int height){	if(!mm_geo) return;	int index=0;        //create a usable grid of points	int pnt_index=0;	for(int z=0; z<height+1; z++)	{		for(int x=0; x<width+1; x++)		{			mm_geo->pnts[pnt_index].alive=1;                           mm_geo->pnts[pnt_index].p=                                    D3DXVECTOR3(x*100.0f,0.0f,z*100.0f);         			pnt_index++;		}	}	//assign info to the triangles	pnt_index=0;	index=0;	for(int a=0; a<width; a++)	{		for(int b=0; b<height; b++)		//notice that both the terms of the "b" loop are offset		//by 1 so that none of the triangles end up in negative space		{			mm_geo->tris[index].alive=1;			mm_geo->tris[index].p[0]=a+b*(width+1);			mm_geo->tris[index].p[1]=(a+1)+(b+1)*(width+1);			mm_geo->tris[index].p[2]=(a+1)+b*(width+1);			mm_geo->tris[index].uv[0][0]=0.0f;			mm_geo->tris[index].uv[0][1]=0.0f;			mm_geo->tris[index].uv[2][0]=1.0f;			mm_geo->tris[index].uv[2][1]=0.0f;			mm_geo->tris[index].uv[1][0]=1.0f;			mm_geo->tris[index].uv[1][1]=1.0f;			mm_geo->tris[index+1].alive=1;			mm_geo->tris[index+1].p[0]=a+b*(width+1);			mm_geo->tris[index+1].p[1]=a+(b+1)*(width+1);			mm_geo->tris[index+1].p[2]=(a+1)+(b+1)*(width+1);			mm_geo->tris[index+1].uv[0][0]=0.0f;			mm_geo->tris[index+1].uv[0][1]=0.0f;			mm_geo->tris[index+1].uv[2][0]=1.0f;			mm_geo->tris[index+1].uv[2][1]=1.0f;			mm_geo->tris[index+1].uv[1][0]=0.0f;			mm_geo->tris[index+1].uv[1][1]=1.0f;			index+=2;		}	}	return;}


Please tell me what you think the reason is that static arrays work fine for the above code but std::vector does not.
Greg Philbrick, Game Developercoming soon . . . Overhauled CellZenith

This topic is closed to new replies.

Advertisement