Ask Question, Ask an Expert

+61-413 786 465

info@mywordsolution.com

Ask C/C++ Expert


Home >> C/C++

Problem #1: plugging the memory leak. When you employ the "normal" new operator, for example Foo* p = new Foo(), the compiler generates some special code to manage the case while the constructor throws an exception. The actual code produced by the compiler is functionally similar to this:

// It is functionally what happens with Foo* p = new Foo() Foo* p;

// don't catch exceptions thrown through the allocator itself void* raw = operator new(sizeof(Foo));

// catch any exceptions thrown through the ctor try {

p = new(raw) Foo(); // call the ctor with raw as this

}

catch (...) {

// oops, ctor threw an exception operator delete(raw);

throw; // rethrow the ctor's exception

}

The point is which the compiler deallocates the memory if the ctor throws an exception. However in particular case of the "new with parameter" syntax (called commonly "placement new"), the compiler won't know that what to do if the exception take places so by default it does nothing:

// It is functionally what happens with Foo* p = new(pool) Foo():

void* raw = operator new(sizeof(Foo), pool);

// the above function returns "pool.alloc(sizeof(Foo))" simply

Foo* p = new(raw) Foo();

// if the above line "throws", pool.dealloc(raw) is NOT called

Thus the goal is to force the compiler to do something same to what it does with the global new operator. Luckily it's simple: while the compiler sees new(pool) Foo(), this looks for a corresponding operator delete. If it determines one, it does the equivalent of wrapping the ctor call in a try block as illustrated above. Thus we would provide simply an operator delete with the following signature (be careful to obtain this right; if the second parameter has a distinct type from the second parameter of the operator new(size_t, Pool&), the compiler doesn't protest; it bypasses the try block simply when your users say new(pool) Foo()):

void operator delete(void* p, Pool& pool)

{

pool.dealloc(p);

}

After this, the compiler will wrap the ctor calls of your new expressions automatically in a try block:

// This is functionally what happens along with Foo* p = new(pool) Foo() Foo* p;

// don't catch exceptions thrown through the allocator itself void* raw = operator new(sizeof(Foo), pool);

// the above returns "pool.alloc(sizeof(Foo))" simply

// catch any exceptions thrown through the ctor try {

p = new(raw) Foo(); // call the ctor along with raw as this

}

catch (...) {

// oops, ctor threw an exception

operator delete(raw, pool); // that's the magical line!!

throw; // rethrow the ctor's exception

}

In other words, the one-liner function operator delete(void* p, Pool& pool) causes the compiler to automagically plug the memory leak. Certainly that function can be, but doesn't need to be, inline.

Problems #2 ("ugly thus error prone") and #3 ("users have to manually associate pool-pointers along with the object that allocated them, that is error prone") are simultaneously solved along an additional 10-20 lines of code in one place. In other terms, we add 10-20 lines of code in one place (your Pool header file) and make simpler an arbitrarily large number of other places (each piece of code which uses your Pool class).

The idea is to implicitly linked a Pool* with every allocation. The Pool* linked with the global allocator would be NULL, however at least conceptually you could say each allocation has linked Pool*. Then you replace the global operator delete thus it looks up the linked Pool*, and if non-NULL, calls that Pool's deallocate function. For instance, if(!) the normal deallocator utilized free(), the replacment for the global operator delete would look something as:

void operator delete(void* p)

{

if (p != NULL) {

Pool* pool = /* somehow get the associated 'Pool*' */;

if (pool == null)

free(p);

else

pool->dealloc(p);

}

}

If you're not definite if the normal deallocator was free(), the simplest approach is also replace the global operator new with something which uses malloc(). The replacement in support of the global operator new would look like this (note: this definition avoid a few details like the new_handler loop and the throw std::bad_alloc() which happens if we run out of memory):

void* operator new(size_t nbytes)

{

if (nbytes == 0)

nbytes = 1; // thus all alloc's get a distinct address void* raw = malloc(nbytes);

...somehow associate the NULL 'Pool*' with 'raw'... return raw;

}

The only remaining difficulty is to linked a Pool* with an allocation. One approach, utilized in at least one commercial product, is to employ a std::map. In other terms, build a look-up table whose keys are allocation-pointer and whose values are the linked Pool*. It is necessary that you insert a key/value pair into the map only in operator new(size_t,Pool&). Particularly, you ought to not insert a key/value pair from the global operator new (for example you have to not say, poolMap[p] = NULL in the global operator new).

Reason: doing that would develop a nasty chicken-and-egg difficulty since std::map probably employ the global operator new, it ends up inserting a new entry each time inserts a new entry, leading to infinite recursion bang you're dead.

Although this technique needs a std::map look-up for each deallocation, it appears to have acceptable performance, at least in several cases.

Another approach which is faster however might use more memory and is a little trickier is to prepend a Pool* just before all of allocations. For instance, if n bytes was twenty four, meaning the caller was asking to allocate 24 bytes, we would allocate 28 (or 32 if the machine need 8-byte alignment for things as doubles and/or long longs), stuff the Pool* to the first four bytes, and return the pointer 4 (or 8) bytes from the starting of what you allocated. After that your global operator delete backs off the 4 (or 8) bytes, determine the Pool*, and if NULL, uses free() or else calls pool- >dealloc(). The parameter passed to free () and pool->dealloc() would be the pointer 4 (or 8) bytes to left of the original parameter, p. If (!) you decide on four byte alignment, your code would look like this (although as before, the following operator new code elides common out-of-memory handlers):

void* operator new(size_t nbytes)

{

if (nbytes == 0)

nbytes = 1; // so all alloc's get a distinct address

void* ans = malloc(nbytes + 4); // overallocate by 4 bytes

*(Pool**)ans = NULL; // use NULL in the global new return (char*)ans + 4; // don't let users see the Pool*

}

void* operator new(size_t nbytes, Pool& pool)

{

if (nbytes == 0)

nbytes = 1; // thus all alloc's get a distinct address

void* ans = pool.alloc(nbytes + 4); // overallocate through 4 bytes

*(Pool**)ans = &pool; // put the Pool* here

return (char*)ans + 4; // don't allow users see the Pool*

}

void operator delete(void* p)

{

if (p != NULL) {

p = (char*)p - 4; // back off to the Pool* Pool* pool = *(Pool**)p;

if (pool == null)

free(p); // note: 4 bytes left of the original p else

pool->dealloc(p); // note: four bytes left of the original p

}

}

Of course the last few paragraphs of this FAQ are viable only while you are allowed to modify the global operator new and operator delete. If you are not allowed to alter these global functions, the primary three quarters of this FAQ is still applicable.

C/C++, Programming

  • Category:- C/C++
  • Reference No.:- M9530113

Have any Question?


Related Questions in C/C++

Project - space race part a console Project - Space Race Part A: Console Implementation

Project - Space Race Part A: Console Implementation INTRODUCTION This assignment aims to give you a real problem-solving experience, similar to what you might encounter in the workplace. You have been hired to complete a ...

1 implement the binary search tree bst in c using the node

1. Implement the Binary Search Tree (BST) in C++, using the Node class template provided below. Please read the provided helper methods in class BST, especially for deleteValue(), make sure you get a fully understanding ...

Software development fundamentals assignment 1 -details amp

Software Development Fundamentals Assignment 1 - Details & Problems - In this assignment, you are required to answer the short questions, identify error in the code, give output of the code and develop three C# Console P ...

Assignment word matchingwhats a six-letter word that has an

Assignment: Word Matching What's a six-letter word that has an e as its first, third, and fifth letter? Can you find an anagram of pine grave. Or how about a word that starts and ends with ant (other than ant itself, of ...

Why do researcher drop the ewaste and where does it end

Why do researcher drop the ewaste and where does it end up?

What are the legal requirements with which websites must

What are the legal requirements with which websites must comply in order to meet the needs of persons with disabilities? Why is maximizing accessibility important to everyone?

Assign ment - genetic algorithmin this assignment you will

ASSIGN MENT - GENETIC ALGORITHM In this assignment, you will use your C programming skills to build a simple Genetic Algorithm. DESCRIPTION OF THE PROGRAM - CORE REQUIREMENTS - REQ1: Command-line arguments The user of yo ...

Question 1find the minimum and maximum of a list of numbers

Question: 1. Find the Minimum and Maximum of a List of Numbers: 10 points File: find_min_max.cpp Write a program that reads some number of integers from the user and finds the minimum and maximum numbers in this list. Th ...

There are several ways to calculate the pulse width of a

There are several ways to calculate the pulse width of a digital input signal. One method is to directly read the input pin and another method (more efficient) is to use a timer and pin change interrupt. Function startTi ...

  • 4,153,160 Questions Asked
  • 13,132 Experts
  • 2,558,936 Questions Answered

Ask Experts for help!!

Looking for Assignment Help?

Start excelling in your Courses, Get help with Assignment

Write us your full requirement for evaluation and you will receive response within 20 minutes turnaround time.

Ask Now Help with Problems, Get a Best Answer

Why might a bank avoid the use of interest rate swaps even

Why might a bank avoid the use of interest rate swaps, even when the institution is exposed to significant interest rate

Describe the difference between zero coupon bonds and

Describe the difference between zero coupon bonds and coupon bonds. Under what conditions will a coupon bond sell at a p

Compute the present value of an annuity of 880 per year

Compute the present value of an annuity of $ 880 per year for 16 years, given a discount rate of 6 percent per annum. As

Compute the present value of an 1150 payment made in ten

Compute the present value of an $1,150 payment made in ten years when the discount rate is 12 percent. (Do not round int

Compute the present value of an annuity of 699 per year

Compute the present value of an annuity of $ 699 per year for 19 years, given a discount rate of 6 percent per annum. As