The new Operator

Microsoft C++ has four versions of the new operator, which allocate objects in the near, far, huge, and based address spaces. The new operator is the only operator or function that can be overloaded on its return type; the only overloading allowed for the return type is on the addressing mode.

By default, the return type of the new operator depends on the memory model under which the program was compiled. For example, in the tiny, small and medium memory models, new returns objects in the near address space.

If you explicitly specify an ambient model for a class, the new operator uses that address space when allocating objects of that class. For example,

class __far Node // Class is far

{

};

Node *pN;

main()

{

pN = new Node; // Far allocation, even if program is

// compiled with a memory model that

// uses near data

}

You can override both the program's memory model and the class's ambient model by explicitly specifying the address space of the object being allocated. To do so, place the __near, __far, __huge or __based keyword after the name of the type. You must use a segment variable with the __based keyword. All the standard conversions between pointers apply, as described in the C++ Language Reference. The following example shows how you can use the various forms of new:

class Node

{

};

Node *pN; // Depends on default memory model

Node __near *npN;

Node __far *fpN;

Node __huge *hpN;

__segment segvar;

Node __based(segvar) *bpN;

main()

{

pN = new Node; // Depends on default memory model

npN = new __near Node;

fpN = new __far Node;

hpN = new __huge Node;

segvar = _bheapseg( 1000 );

bpN = new __based(segvar) Node;

fpN = new __near Node; // Convert near to far

fpN = new __based(segvar) Node; // Convert based to far

npN = new __far Node; // Error: cannot convert

// from far to near

}

You can write your own version of the new operator if you want to use a customized memory allocation scheme (for instance, one that provides zero-initialized storage or one that's optimized for your program's pattern of memory usage). The new operator that you define must have the same return type and arguments as the one you want to replace. To do this, you must use one of the following prototypes:

void __near *operator new( size_t size );

void __far *operator new( size_t size );

void __huge *operator new( unsigned long elems, size_t size );

void __based(void) *operator new( __segment segvar, size_t size );

The argument of type size_t is automatically set to the size of the object being allocated. You can also define class-specific versions of any of these forms of new.

Summary: The new operator for huge objects behaves like an array allocator.

The new operator for huge objects behaves like an array allocator, even if only one object is being allocated. It receives two arguments: the number of elements being allocated and the size of each element. If the total size of the array is larger than 128K, the element size must be a power of 2.

The new operator for based objects has an additional argument, which is a segment variable. This argument receives the value of the segment used in the allocation expression.

When you redefine the new operator, you can make your version of the operator accept additional arguments, known as “placement arguments.” These arguments must appear last when you declare new's argument list, but they must appear before the type name and in parentheses when you call new. For example, to define a new operator for based objects that takes a short integer as a placement argument, you would use the following prototype:

void __based(void) *operator new( __segment segvar, size_t size, short place );

This prototype permits expressions like

bpN = new __based(segvar) (112) Node;

The placement argument receives the value 112 as a short integer.

All of the default new operators have the __cdecl calling convention.