10

I am working on a plugin for an application, where the memory should be allocated by the Application and keep track of it. Hence, memory handles should be obtained from the host application in the form of buffers and later on give them back to the application. Now, I am planning on using STL Vectors and I am wondering what sort of memory allocation does it use internally.

Does it use 'new' and 'delete' functions internally? If so, can I just overload 'new' and 'delete' with my own functions? Or should I create my own template allocator which looks like a difficult job for me since I am not that experienced in creating custom templates.

Any suggestions/sample code are welcome. Memory handles can be obtained from the application like this

void* bufferH = NULL;

bufferH = MemReg()->New_Mem_Handle(size_of_buffer);
MemReg()->Dispose_Mem_Handle(bufferH); //Dispose it
rwb
  • 621
  • 1
  • 12
  • 21
  • For creating your own allocator see this classic by Matt Austern: http://www.drdobbs.com/184403759 – sbi Nov 11 '10 at 22:09
  • @sbi: I haven't read that yet, but recall that allocator semantics changed significantly in C++11. Are you sure that classic is still relevant today? (That is not a rhetorical question but a real one.) – einpoklum Jan 15 '16 at 14:28
  • 1
    @einpoklum That is a 6 year old comment. We have two new standard versions and another one on the horizon. Of course things might have changed since then. – sbi Jan 25 '16 at 22:46

5 Answers5

18

vector uses std::allocator by default, and std::allocator is required to use global operator new (that is, ::operator new(size_t)) to obtain the memory (20.4.1.1). However, it isn't required to call it exactly once per call to allocator::allocate.

So yes, if you replace global operator new then vector will use it, although not necessarily in a way that really allows your implementation to manage memory "efficiently". Any special tricks you want to use could, in principle, be made completely irrelevant by std::allocator grabbing memory in 10MB chunks and sub-allocating.

If you have a particular implementation in mind, you can look at how its vector behaves, which is probably good enough if your planned allocation strategy is inherently platform-specific.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • 1
    Other containers can benefit from custom allocators, though. For certain applications, a pool allocator can drastically improve the performance of node-based containers like `std::map`. – James McNellis Nov 11 '10 at 22:03
  • 1
    Small object allocation is also one of Alexandrescu's favourite topics - http://stackoverflow.com/questions/2707909/how-do-i-use-lokis-small-object-allocator – Steve Townsend Nov 11 '10 at 22:06
  • Thanks for the replies. I shouldn't have used the word 'efficient'. I meant that the application is supposed to allocate 'all' the memory and keep track of it no matter of its size or efficiency. But from your comment, it looks like overloading new and delete should work fine. – rwb Nov 11 '10 at 22:43
6

STL containers use an allocator they are given at construction time, with a default allocator that uses operator new and operator delete.

If you find the default is not working for you, you can provide a custom allocator that conforms to the container's requirements. There are some real-world examples cited here.

I would measure performance using the default first, and optimize only if you really need to. The allocator abstraction offers you a relatively clean way to fine-tune here without major redesign. How you use the vector could have far more performance impact than the underlying allocator (reserve() in advance, avoid insert and removal in the middle of the range of elements, handle copy construction of elements efficiently - the standard caveats).

Community
  • 1
  • 1
Steve Townsend
  • 53,498
  • 9
  • 91
  • 140
  • @James, @GMan: There are a couple of specific aspects that are unspecified though -- particularly, when and how often `std::allocator` uses `::operator new` to obtain memory, and how (or even if) the `hint` parameter is used. – Jerry Coffin Nov 11 '10 at 22:08
  • Thanks for the reply Steve. I do reserve the vector in advance and avoid removal and insert of middle range elements. But I wasn't sure overloading new and delete would make it use the memory allocated by the host application. My apologies for using the word 'efficient'. – rwb Nov 11 '10 at 22:48
  • No apology needed, writing for the broader audience as well as to you... it's possible you need to clarify the memory ownership to get best specific answer. What do you plan to store, where does its memory come from, how does it get released? A minimal sample code would help. – Steve Townsend Nov 11 '10 at 22:51
  • Sample code added to illustrate how to get handles from the application. I plan on to store float values (OpenGL vertices). – rwb Nov 11 '10 at 23:02
  • 1
    @gutsblow - if this is your only path to allocate memory, then I can't see how you can avoid writing a custom allocator to encapsulate the `host_new_handle` and `host_dispose_handle` APIs. – Steve Townsend Nov 11 '10 at 23:21
  • So, if overload both 'new' and 'delete' with functions that encapsulate host_new_handle and host_dispose_handle, doesn't that mean STL also gets memory from those functions? – rwb Nov 11 '10 at 23:37
  • My idea was to create a header that contains those functions and force include it in every file. Not sure, if its the best way to do it but certainly the easiest way (only if it works). – rwb Nov 11 '10 at 23:39
  • 1
    Yes but I am not sure of the scope of such a change given that you are a library in a host application - see here: http://stackoverflow.com/questions/2007274/a-library-forces-global-overloads-of-new-delete-on-me. Why not create your own allocator - a class template that wraps `std::allocator` but overloads `operator new` and `operator delete` at the class level? – Steve Townsend Nov 11 '10 at 23:42
  • Thanks for the link, I'll sure check it out. Yes, making a custom allocator is the right thing to do, so I'll go ahead with it even if it takes some time. – rwb Nov 12 '10 at 18:33
  • Good luck - there are plenty of models online, just make sure you pick one that works to follow. – Steve Townsend Nov 12 '10 at 18:36
3

std::vector uses the unitialized_* functions to construct its elements from raw memory (using placement new). It allocates storage using whatever allocator it was created with, and by default, that allocator uses ::operator new(size_t) and ::operator delete(void *p) directly (i.e., not a type specific operator new).

MSN
  • 53,214
  • 7
  • 75
  • 105
2

From this article, "The concept of allocators was originally introduced to provide an abstraction for different memory models to handle the problem of having different pointer types on certain 16-bit operating systems (such as near, far, and so forth)" ...

"The standard provides an allocator that internally uses the global operators 'new' and 'delete'"

The author also points out the alocator interface isn't that scary. As Neil Buchanan would say, "try it yourself!"

Rooke
  • 2,013
  • 3
  • 22
  • 34
2

The actual std::allocator has been optimized for a rather large extent of size objects. It isn't the best when it comes to allocating many small objects nor is it the best for many large objects. That being said, it also wasn't written for multi-threaded applications.

May I suggest, before attempting to write your own you check out the Hoard allocator if you're going the multi-threaded route. (Or you can check out the equally appealing Intel TBB page too.)

wheaties
  • 35,646
  • 15
  • 94
  • 131