tags:

views:

366

answers:

6

Hey,

So the question is relatively straight forward, I have several semi-large lookup tables ~500kb a piece. Now these exact same tables are used by several class instantiations (maybe lots), with this in mind I don't want to store the same tables in each class. So I can either dump the entire tables onto the stack as 'static' members, or I can have 'static' pointers to these tables. In either case the constructor for the class will check whether they are initialized and do so if not. However, my question is, if I choose the static pointers to the tables (so as not to abuse the stack space) what is a good method for appropriately cleaning these up.

Also note that I have considered using boost::share_ptr, but opted not to, this is a very small project and I am not looking to add any dependencies.

Thanks

+1  A: 

If you don't free the memory for the tables at all, then when your program exits the OS will automatically throw away all memory allocated by your application. This is an appropriate strategy for handling memory that is allocated only once by your application.

Leaving the memory alone can actually improve performance too, because you won't waste time on shutdown trying to explicitly free everything and therefore possibly force a page in for all the memory you allocated. Just let the OS do it when you exit.

Greg Hewgill
However leak checking tools like valgrind, etc, will complain about unfreed memory at exit.
bdonlan
That's true, but such warnings can be ignored or explicitly suppressed.
Greg Hewgill
It can sometimes be easier to avoid making errors in suppressing those warnings (what if you suppress a legitimate warning?) by actually freeing the memory in question.
bdonlan
and this stratagem limits future use of the code in a larger application who may only need the lookup tables occasionally and the resources are best used elsewhere.
Ape-inago
I definitely thought about just letting the OS cleanup, just seemed messy to me, although theoretically there is nothing wrong with it.
DeusAduro
A: 

If these are lookup tables, the easiest solution is just to use std::vector:

class SomeClass {
  /* ... */
  static std::vector<element_type> static_data;
};

To initialize, you can do:

static_data.resize(numberOfElements);
// now initialize the contents

With this you can still do array-like access, as in:

SomeClass::static_data[42].foo();

And with any decent compiler, this should be as fast as a pointer to a native array.

bdonlan
+4  A: 

Static members will never be allocated on the stack. When you declare them (which of course, you do explicitly), they're assigned space somewhere (a data segment?).

If it makes sense that the lookup tables are members of the class, then make them static members!

When a class is instanced on the stack, the static member variables don't form part of the stack cost.

If, for instance, you want:

class MyClass {
    ...
    static int LookUpTable[LARGENUM];
};

int MyClass:LookUpTable[LARGENUM];

When you instance MyClass on the stack, MyClass:LookUpTable points to the object that you've explicitly allocated on the last line of the codesample above. Best of all, there's no need to deallocate it, since it's essentially a global variable; it can't leak, since it's not on the heap.

Dave Gamble
Arrays as static members will only work if the array size is fixed, of course.
bdonlan
Reading around it sounds like where static members/variables are stored is actually undefined (in the general sense) and is compiler specific.
DeusAduro
Best I can tell, they live next-door to the const char * "Hello World" ;)
Dave Gamble
I really do like your solution, I guess the test in my case is to see how big of a lookup table I can add in this manner. The MSDN documentation tells me default maximum stack space for a program is 1MB, so I'll give it a try!
DeusAduro
Nah, string literals will be in the read-only data section. Read-write data is the next page over :)
bdonlan
@Deus, this has nothing to do with the stack, so the stack size limit won't apply. You'll be limited by maximum BSS space (is that the term on windows?) which is likely to be hundreds of megabytes at least.
bdonlan
Alrighty I'll take your word/s for it. This was my original choice, but I always that it was bad (or maybe just frowned upon) practice to non-dynamically allocate large chunks of memory, ie. int hugeArray[LARGE_NUMBER];.
DeusAduro
It is not completely impossible that you might see this reflected in the size of your executable.
Dave Gamble
No change in the executable size, and it works nicely. Thanks again.
DeusAduro
+1  A: 

Why don't you create a singleton class that manages the lookup tables? As it seems they need to be accessed by a number of classes; make the singleton the manager of the lookup tables accessible at global scope. Then all the classes can use the singleton getters/setters to manipulate the lookup tables. There are 3 advantages to this approach:-

  • If the static container size for the lookup tables becomes large then the default stack-size may ( 1MB on Windows) lead to stack-overflow on application statrt-up itself. Use a container that allocates dynamically.

  • If you plan to access the table via multiple-threads, the singleton class can be extended to accompany locked access.

  • You can also cleanup in the dtor of singleton during application exit.

Abhay
A: 

I can think of several ways to approach for this depending upon what is trying to be accomplished.

If the data is static and fixed, using a static array which is global and initialized within the code would be a good approach. Everything is contained in the code and loaded when the program is started so it is available. Then all of the class which need access can access the information.

If the data is not static and needs to read in, an static STL structure, such as a vector, list or map would be good as it can grow as you add elements to the list. Some of these class provides lookup methods as well. Depending upon the data you are looking up, you may have to provide a structure and some operator to have the STL structures work correctly.

In either of the two case, you might what to make a static global class to read and contain the data. It can take care of managing initialization and access the data. You can use private members to indicate if the class has been read in and is available for use. If it has not, the class might be able to do the initialization by itself if it has enough information. The other class can call static function of the static global class to access the data. This provides encapsulation of the data, and then it can be used by several different classes without those classes needing to incorperate the large lookup table.

Glenn
A: 
Mark Santesson