CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 12 of 12

Thread: Replacing global new and delete

  1. #1
    Join Date
    Jun 2007
    Location
    Vercelli, Italy
    Posts
    87

    Question Replacing global new and delete

    Hi everyone! I've been reading many an article on this matter, but I want to make sure I've understood everything correctly. The thing is, that I couldn't find any source that explicitly "validated" what I plan to do in my specific case, so I though I'd ask more experienced people than me.

    I want to replace global operators new and delete. There are two reasons I want to do this, and to each of them corresponds a "step" I want to be sure of:

    1) I want to do some simple tracking of my allocations; keeping a record of how much memory I allocated in the heap, and who allocated it, should help me in spotting memory leaks;

    2) I may want to do in the future some sort of custom memory allocation. While I know this is usually a form of optimization, and it's wrong to optimize early in the project, I would like to create something which will allow me to drop in a custom allocator without too much hassle.

    From what I've got, point 1 is very easy to achieve. Basically I only need to define an overload of the global new with additional parameters, like:
    Code:
     void* operator new(size_t size, const char* file, const char* function /*, more parameters as needed */)
    Of course, I'll have to define a symmetric delete operator that takes the same arguments, to avoid leaks should the constructor throw an exception. Question #1: if I don't use exceptions in my code, do I still have to define this delete overload? Do I need to worry about the nothrow overloads, or is it safe to ignore them?

    At first I wondered what would happen if I also replaced the default delete definition (the delete(void* ptr) one). Let's suppose my new/delete overloads use malloc()/free(); the objects I create will be created with malloc() and deleted with free(), but the objects that third-party code would create (with the "regular" new operator) would be deleted with free(), but I could not be sure whether they were created with malloc(). This, of course, would be bad.

    Then I figured that my overloads of new and delete could, in fact, simply call the regular new and delete after they did their record-keeping stuff. This way, all of the objects (both mine and third-parties') would be created with the allocator used by the C++ implementation, and deleted with the very same allocator. I've read articles that confirm this idea; is this correct (question #2)? I have to ask because it's hard for me to write a test for this kind of problems; maybe I'm just being lucky and using by chance the same allocator my compiler uses; maybe I just didn't make a test valid enough to observe bad behaviour when I do something wrong.

    The second reason why I need to fiddle with new and delete seems to be way trickier. From what I've got, to implement a custom allocator I would be better off splitting the two operations performed by new. So, in my "step 2" overload of new there would be
    a) the record-keeping stuff
    b) allocation of memory by the allocator - something like
    Code:
    void* pObject = MemoryAllocator::Allocate(size);
    c) construction of the object via non-overloaded placement new

    Symmetrically, my "step 2" delete would feature
    a) the record-keeping stuff
    b) destruction of the object with an explicit call of the destructor method
    c) deallocation of the memory pointed to: MemoryAllocator::Free(ptr)

    Question #3: is it correct that I have to use operator new placement with a custom allocator? As far as I know, I can't pass an allocator object to new. What I am confused about, is: how would I know the class of the object to construct? The same applies for the destructor.

    Question #4: would it be a better choice to leave the new/delete operators as they were in step 1 (i.e., with the call to the regular operators), and to proceed to override them on a class basis, so that I can define a base class for all the objects that will need a particular allocator (say, class PooledObject, which all objects that need to be pooled will derive from), while leaving the rest of the allocations untouched?

    Also, marginally, question #5: should the record-keeping code go before or after the construction/destruction of the object? Of course it's wise to not separate allocation from construction (and destruction from deallocation). I guess it would be better to do the construction first, and then the record-keeping, so that the construction is not recorded if something goes wrong (exceptions); symmetrically, destroy the record (if it exists) then destroy the object. Am I correct?

    Thanks a lot for the patience to read all of this! :-)
    I owe Paul McKenzie a pizza.

    I am no expert; but they say I can make concepts easy to understand. That's why newbies questions are mine!!! XD

  2. #2
    Join Date
    May 2009
    Posts
    2,413

    Re: Replacing global new and delete

    ---
    Last edited by nuzzle; August 16th, 2010 at 10:46 PM.

  3. #3
    Join Date
    Jun 2007
    Location
    Vercelli, Italy
    Posts
    87

    Re: Replacing global new and delete

    Thanks Nuzzle. Your reply was not really spot-on, but it gave me an interesting thing to observe: operator new only takes care of the memory allocation, and not of the construction of the object.

    Here's the code of my current operator new - the one I labelled "step 1" in my opening post:
    Code:
    void* operator new(size_t size, const char* file, size_t line, const char* function)
    {
    	void* ptr = ::operator new(size);
    	Utilities::MemoryManager::GetInstance().RecordAllocation(ptr, size, file, line, function);
    	return ptr;
    }
    With breakpoints on operator new(size) and on the first line of the constructor, I was able to see that the operator new (the one you see above) is called first, completely executed (i.e., regular new, record-keeping, and return), *then* the constructor is executed.

    So, I don't need to worry about constructing and destructing the objects. It is enough (and Nuzzle's example shows it for good) to take care of memory allocation and deallocation; the compiler will automagically call the ctor/dtor where appropriate.

    I checked this behaviour in MS Visual Studio C++ Express 2009; does anybody know if this is part of the standard, or whether this is supported by a large number of compilers? I'm mainly interested in MS's ones and in GCC.
    I owe Paul McKenzie a pizza.

    I am no expert; but they say I can make concepts easy to understand. That's why newbies questions are mine!!! XD

  4. #4
    Join Date
    May 2009
    Posts
    2,413

    Re: Replacing global new and delete

    Quote Originally Posted by Sk# View Post
    Your reply was not really spot-on
    You can't appreciate the considerable value of a practical working example?

    Well, don't worry, I'll remove it.
    Last edited by nuzzle; August 16th, 2010 at 10:50 PM.

  5. #5
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: Replacing global new and delete

    You should try to understand more in details how new works, in particular the difference between the new operator and operator::new, and what their respective jobs are.

    the keyword new, also know as the "new operator" first calls "operator::new", providing it with a certain amount of arguments. operator::new's job is to allocate* as much memory as requested by the new operator. How it does it depends on the arguments passed.

    Once operator::new is done, it returns a pointer to the new operator, and the new operator is then responsible for constructing the object (objects in case of new[]) at the place returned by operator::new.

    operator::new is over-loadable. the new operator is a non-overloadable keyword.

    *operator::new's job is not actually allocating memory, but rather giving the new operator a place to construct its object.

    ---

    Now for my 2 cents: All of this is pointless. I have NEVER (EVER) seen anybody actually overload operator new. ever. I can understand doing it for the fun of learning (I have).

    What I could recommend though is to make a custom allocator. These are more powerful and polyvalent objects that can suit your future needs, without changing the global behavior of new.

    Also, I know for a fact the GCC provides a lot of safe/checked allocators. Try to read about those before steamrolling out your own application.
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  6. #6
    Join Date
    Jun 2007
    Location
    Vercelli, Italy
    Posts
    87

    Re: Replacing global new and delete

    Quote Originally Posted by nuzzle View Post
    You can't appreciate the considerable value of a practical working example?

    Well, don't worry, I'll remove it.
    No, don't get me wrong: your example was gold and it was very helpful. Sorry if that didn't come out. What I meant was that you didn't really answer my questions, though the example gave me useful hints.

    Please, restore the example - if not for me, for those who will search this topic in the future.

    Quote Originally Posted by monarch_dodra View Post
    You should try to understand more in details how new works, in particular the difference between the new operator and operator::new, and what their respective jobs are.

    [...]
    I swear, I had never heard about such a difference! I'll be sure to research more now that you pointed this out, because this explains what I had observed in my previous post.

    Quote Originally Posted by monarch_dodra View Post
    Now for my 2 cents: All of this is pointless. I have NEVER (EVER) seen anybody actually overload operator new. ever. I can understand doing it for the fun of learning (I have).

    What I could recommend though is to make a custom allocator. These are more powerful and polyvalent objects that can suit your future needs, without changing the global behavior of new.

    Also, I know for a fact the GCC provides a lot of safe/checked allocators. Try to read about those before steamrolling out your own application.
    Thanks, I'll look them up. It wasn't clear from my post, but I don't plan to write an allocator myself from scratch; though I will probably have to use a "custom" one - custom in the sense that it's not the default one.

    If I'm not wrong, though - and Nuzzle's example proved it, - when I use a custom allocator I have to drop it in my project, and its "entry point" would be operator new, am I wrong? So I need to override the default operator, to make it allocate memory (pardon, find a place to construct the object) using the custom allocator.

    Also, would the allocator keep track of allocations? Well, probably yes, but I'm interested in those extra information, and apparently I'm doing no harm by just wrapping operator new in a record-keeping function. Am I correct? There may be bad things I'm doing that I don't see.
    I owe Paul McKenzie a pizza.

    I am no expert; but they say I can make concepts easy to understand. That's why newbies questions are mine!!! XD

  7. #7
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: Replacing global new and delete

    an allocator (in the stl sense of the word) is basically an instantiable new-functor. The problem with new is that it is global. If you overload-it, you overload it for the entire project. With allocators, you can have several different allocators co-existing, each providing their own allocating scheme. If you have ever wondered what the second parameter of a std::vector, that's what it is.

    http://www.cplusplus.com/reference/s...ory/allocator/ is the default stl allocator, and basically wraps new. You can create your own, and provided you keep the same interface as the stl's, you can have a vector using your own allocating scheme.

    Quote Originally Posted by Sk# View Post
    Also, would the allocator keep track of allocations?
    They can do whatever you want. I believe that in debug in GCC, the default allocator does this by default.
    Last edited by monarch_dodra; August 17th, 2010 at 04:39 AM.
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  8. #8
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: Replacing global new and delete

    Quote Originally Posted by monarch_dodra View Post

    http://www.cplusplus.com/reference/s...ory/allocator/ is the default stl allocator, and basically wraps new.
    I'm no expert, but I would guess that it's actually wrapping malloc, since I know std::vector uses placement new internally to avoid constructing objects in the "unused" portion of its capacity until necessary.

  9. #9
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: Replacing global new and delete

    Quote Originally Posted by Lindley View Post
    I'm no expert, but I would guess that it's actually wrapping malloc, since I know std::vector uses placement new internally to avoid constructing objects in the "unused" portion of its capacity until necessary.
    Allow me to correct myself: it calls operator::new. This allocates memory, but does not construct an object on the allocated spot.

    GCC implements std::allocate by deriving from the base class ext/new_allocator, which does this:

    Code:
          pointer
          allocate(size_type __n, const void* = 0)
          { 
        if (__builtin_expect(__n > this->max_size(), false))
          std::__throw_bad_alloc();
    
        return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
          }
    
          // __p is not permitted to be a null pointer.
          void
          deallocate(pointer __p, size_type)
          { ::operator delete(__p); }
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  10. #10
    Join Date
    Feb 2002
    Posts
    4,640

    Re: Replacing global new and delete

    Quote Originally Posted by monarch_dodra View Post
    Now for my 2 cents: All of this is pointless. I have NEVER (EVER) seen anybody actually overload operator new. ever. I can understand doing it for the fun of learning (I have).
    I realize this is your $0.02, but I have overloaded operator new and delete for a parser token class. The class would keep a cache of tokens and when the parser "allocated" a new one, the class would just pass it an already used one.

    Not only did parsing large files speed up, it used less memory.

    Viggy

  11. #11
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: Replacing global new and delete

    The matrix library Eigen overloads new and delete to ensure its matrices have a particular memory alignment, so that it can automatically generate SSE-accelerated code.

  12. #12
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: Replacing global new and delete

    Hehe, not saying it can't be done, I just said I had never personally seen it.
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width




On-Demand Webinars (sponsored)