3

Currently, I have all my objects managing their own memory, allocating with new in their constructors typically, and using delete in their destructors. This works for now, but the number of classes I have that use arbitrary amounts of memory is growing. The fact that new is essentially a "request" also bothers me, since these objects have no code within them to handle being told "no", and I don't want to rely on Exception Handling if I do not need to.

  • Is it beneficial in terms of performance to completely shield all calls that allocate memory, to a single class that handles every memory allocation on the heap, probably allocating large chunks at a time and using placement new to deal out references?

  • Is the use of memory allocation in smaller classes a big enough concern to even bother with this?

  • Can I still use STL containers and force them to use the heap I provide?

Thank you in advance!

Anne Quinn
  • 12,609
  • 8
  • 54
  • 101
  • 2
    "these objects have no code within them to handle being told "no", and I don't want to rely on Exception Handling if I do not need to" - what other way were you thinking of handling this? You either have a check, or an exception. Memory isn't infinite, so there are no other options. – Merlyn Morgan-Graham Sep 18 '11 at 00:25
  • 1
    @merlyn - If I centralize it into a class, the check would occur within the memory management class upon request. I then only need to place all the code needed there. For instance, I can prompt the user to free memory, or halt the program while it attempts to allocate memory again. Or just terminate at that point then and there. – Anne Quinn Sep 18 '11 at 00:29
  • 1
    You still have all these options with exception handling, and you can put the code where it belongs - higher level code that understands what is going on in the system (so can do deallocations then retry the operation, or display a message to the user). Of course you can argue that there should be a "check if there is enough space" method for your allocator, so you can do this before throwing an exception... – Merlyn Morgan-Graham Sep 18 '11 at 00:38
  • 2
    "For instance, I can prompt the user to free memory, or halt the program while it attempts to allocate memory again. Or just terminate" - that's what `std::set_new_handler` is for. Beware also that it's quite hard to display a message to the user in a low-memory situation, you have to be sure you've allocated all the necessary resources well ahead of time. – Steve Jessop Sep 18 '11 at 00:57
  • @Steve - I did not know that existed. That's... exactly what I have been looking for, thanks! (I suppose for displaying a message, reserving the memory to do so at the very start for critical use would help) – Anne Quinn Sep 18 '11 at 01:03
  • @Clairvoire: there's two basic strategies that I know of. One is to reserve the specific resources required (a hidden window or whatever, that you can display without allocating memory). The other is to reserve a biggish chunk of memory, and free that before trying to display the message in the expectation that you need less memory than you've just made available. The first may not work for you, since in a typical GUI there's allocation hidden behind the scenes, according to what "prompt" means in your case. The second involves a magic number that you probably arrive at by guesswork or trial. – Steve Jessop Sep 18 '11 at 01:10
  • @Clairvoire: You'll need OS-specific code to deal with that message. On Windows, the sanctioned method is `MessageBoxW`. Not the `A` variant, that has to convert your 8 bit strings to 16. Also, don't use strings from your resource section, or created by string concatenation - use hardcoded strings. The `MB_ICONERROR` icon is also pre-allocated for precisely this case. – MSalters Sep 19 '11 at 09:06

5 Answers5

4

Can I still use STL containers and force them to use the heap I provide?

STL containers accept custom allocators:

http://en.wikipedia.org/wiki/Allocator_(C%2B%2B)#Custom_allocators

Here is a thread with links to samples:

Compelling examples of custom C++ allocators?

Is it beneficial in terms of performance ... ?

You can only find out by writing your application, coming up with a set of reproducible test scenarios, and running your code in a profiler. If you find the memory allocation to be a significant portion of the running time, then you might benefit from a better allocation strategy.

If you can break up your program to a feature level, and can come up with realistic scenarios for each case, you don't have to have your whole program working to do this. But remember that time spent optimizing is time that could be spent testing or coding new features :) Do what is necessary and no more...

Is the use of memory allocation in smaller classes a big enough concern to even bother with this?

Depending on your program, how sensitive you are to big allocation hitches, how often you allocate in loops, etc, it is possible. Profile :)

While developing your app, you can still be sensitive to allocations - create automatic storage (stack local) variables when you can, and allocate dynamically only when you must.

Community
  • 1
  • 1
Merlyn Morgan-Graham
  • 58,163
  • 16
  • 128
  • 183
  • Understood! My profiler only sees it as a minor problem in contact-pair generation for some physics stuff. At this point though, I just want to place my error-checking code someplace, so I don't have to put boilerplate code everywhere. Performance gain was just something I was curious about – Anne Quinn Sep 18 '11 at 00:58
  • @Clairvoire: You could also consider putting your error checking code in a factory method/class. – Merlyn Morgan-Graham Sep 18 '11 at 01:00
3

I'm not really sure I understand your problem here. That said, using STL containers in C++03 with your custom heap will be challenging, since allocators are considered stateless. Also, why don't you want to rely on exception handling? Are you aware that there is a no_throw version of new?

Edit: The no-throw version of new is invoked like this: new (std::nothrow) Type[size];. If the allocation fails, it will return a null pointer (0) instead of throwing std::bad_alloc.

K-ballo
  • 80,396
  • 20
  • 159
  • 169
  • I did not know :) How do you invoke the no_throw version of `new`? Can you add this to your answer? – Merlyn Morgan-Graham Sep 18 '11 at 00:35
  • I am aware, but using no_throw means I have to check for NULL. Not a problem in itself, but classes at that level usually can't recover from being denied memory. As for exception handling, it's just a preference is all. – Anne Quinn Sep 18 '11 at 00:37
3

Can I still use STL containers and force them to use the heap I provide?

Yes, look up STL allocators.

Is it beneficial in terms of performance to completely shield all calls that allocate memory, to a single class that handles every memory allocation on the heap, probably allocating large chunks at a time and using placement new to deal out references?

That's basically what a good implementation of malloc or new does. I disrecommend doing it yourself unless the situation is very performance-critical and everything else has been optimized. Why? Because good and well-thought through memory management is very hard to even get bug-free, let alone working optimized.

Is the use of memory allocation in smaller classes a big enough concern to even bother with this?

It depends, if you're programming a coffee machine or gaming device with 16k of memory, perhaps, but on a regular desktop computer or laptop probably not. Also remember that the stack is very fast (allocation and access) while the heap is a lot worse on allocation and slightly (not so sure about that TBH) on usage so in day to day situations you want to prefer the stack.

orlp
  • 112,504
  • 36
  • 218
  • 315
2

I've done this before, and here's my experience:

  1. It can get very messy very quickly. Especially since you now take memory allocation into your hands and you have to deal with stuff like fragmentation and re-entrancy.
  2. However, I've seen performance boosts upwards of 20% due to being able to bypass the OS overheads.

For your last question, I think there is a way to make them use a custom allocator, but I've never done it before. I do most of my coding in C.

EDIT:

Based on your comment, here's an update. You don't really have to deal with building an allocator. You can probably get away with just pointing all memory allocations to your custom class. Then your custom class will call malloc() or new and catch whatever NULL or exception is returned.

(Though it will take some work replacing every single new with your own malloc().)

Mysticial
  • 464,885
  • 45
  • 335
  • 332
2

You say you're calling new in your constructors... Is that really necessary? I mean, instead of this...

class A{
    std::vector<int>* v;
    A( int vectorSize ){
       v = new std::vector<int>( vectorSize, 0 );
    }
    ~A(){
       delete v;
    }
};

...it's always preferrable to do this:

class A{
    std::vector<int> v;
    A( int vectorSize ):
       v( vectorSize, 0 ){
    }
};

This way you avoid using the heap. You should only use the heap when you have no other choice.

Asides from that, like the others said, writing your custom allocator is a very complex task and should only be done in a performance-critical scenario

dario_ramos
  • 7,118
  • 9
  • 61
  • 108
  • 1
    `std::vector v;` allocates the container itself on the stack, but I've been under the impression that the actual memory the container uses is created on the heap. – Anne Quinn Sep 18 '11 at 00:43
  • 1
    Ah, now I see what you mean. Since `vectors` need to grow dynamically, they have no other choice than using the heap. Though they might avoid it if they allocate sufficient initial space on the stack, and only request heap space if they surpass that limit. Anyway, it's a very implementation-specific detail. Visual Studio might do it differently than, say, gcc. – dario_ramos Sep 18 '11 at 00:48
  • +1; Upvote because this is a good suggestion, even if on closer inspection not applicable. – Merlyn Morgan-Graham Sep 18 '11 at 01:07