class A
{
public:
A();
~A();
};
A *p = new A;
...
delete p;
allocates storage for an A object and arranges for its constructor to be called, later followed by invocation of the destructor and freeing of the storage. You can use the standard new/delete functions in the library, or define your own globally and/or on a per-class basis.
There's a variation on new/delete worth mentioning. It's possible to supply additional parameters to a new call, for example:
A *p = new (a, b) A;
where a and b are arbitrary expressions; this is known as "placement new". For example, suppose that you have an object instance of a specialized class named Alloc that you want to pass to the new operator, so that new can control allocation according to the state of this object (that is, a specialized storage allocator):
class Alloc {/* stuff */};
Alloc allocator;
...
class A {/* stuff */};
...
A *p = new (allocator) A;
If you do this, then you need to define your own new function, like this:
void* operator new(size_t s, Alloc& a)
{
// stuff
}
The first parameter is always of type "size_t" (typically unsigned int), and any additional parameters are then listed. In this example, the "a" instance of Alloc might be examined to determine what strategy to use to allocate space. A similar approach can be used for operator new[] used for arrays.
This feature has been around for a while. A relatively new feature that goes along with it is placement delete. If during object initialization as part of a placement new call, for example during constructor invocation on a class object instance, an exception is thrown, then a matching placement delete call is made, with the same arguments and values as to placement new. In the example above, a matching function would be:
void operator delete(void *p, Alloc &a)
{
// stuff
}
With new, the first parameter is always "size_t", and with delete, always "void*". So "matching" in this instance means all other parameters match. "a" would have the value as was passed to new earlier.
Here's a simple example:
int flag = 0;
typedef unsigned int size_t;
void operator delete(void *p, int i)
{
flag = 1;
}
void* operator new(size_t s, int i)
{
return new char[s];
}
class A
{
public:
A() {throw -37;}
};
int main()
{
try
{
A *p = new (1234) A;
}
catch (int i)
{
}
if (flag == 0)
return 1;
else
return 0;
}
Placement delete may not be in your local C++ compiler as yet. In compilers without this feature, memory will leak. Note also that you can't call overloaded operator delete directly via the operator syntax; you'd have to code it as a regular function call.
In addition to the language providing this general capability, the C++ standard library also provides a specific instance for void*:
void* operator new(size_t, void*);
void operator delete(void*, void*);
These are accessed by saying:
#include
These functions are defined to do nothing (though new returns its argument). Their purpose is to allow construction of an object at a specific address, which is often useful in embedded systems and other low-level applications:
const unsigned long MEMORY_MAP_IO_AREA = 0xf008;
...
Some_Class* p = new ((void*) MEMORY_MAP_IO_AREA) Some_Class();
Based on a fairly recent decision of the standards committee, this definition of placement new/delete for void* is reserved by the library, and cannot be replaced by the user (unlike the normal global operator new, which can be). The library also defines a similar placement new/delete for allocating arrays at a specific address.
No comments:
Post a Comment