C++.Coding.Standards.1918.Rules.Guidelines [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

C++.Coding.Standards.1918.Rules.Guidelines [Electronic resources] - نسخه متنی

Herb Sutter, Andrei Alexandrescu

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید


Discussion


You rarely need to provide a custom

new or

delete , but if you need one you usually need both. If you de fine a class-specific

T::operator new to do some special allocation, it's very likely you need to define a class-specific

T::operator delete as well to do the corresponding special deallocation.

That much may be somewhat basic, but there is a subtler reason for this Item: The compiler might be yearning for an overload of

T::operator delete even when you never actually invoke it. That's why you always need to provide

operator new and

operator delete (and

operator new[] and

operator delete[] ) in pairs.

Say you define a class with customized allocation:

class T {

// …
static void* operator new(std::size_t);
static void* operator new(std::size_t, CustomAllocator&);
static void operator delete(void*, std::size_t);
};

You establish a simple protocol for allocation and deallocation:

  • Callers can allocate objects of type

    T with either the default allocator (using

    new T ) or the custom allocator (using

    new(alloc) T where

    alloc is an object of type

    CustomAllocator ).

  • The only

    operator delete that callers can ever invoke is the default

    operator delete(size_t) , so of course you implement such that it correctly deallocates memory allocated either way.


So far, so good.

However, the compiler still needs to covertly call another overload of

delete , namely

T::operator delete(size_t, CustomAllocator&) . This is because the statement

T* p = new(alloc) T;

really expands into something like

// compiler-generated code for T* p = new(alloc) T;

//
void* __compilerTemp =

T::operator new(sizeof(T), alloc) ;
T* p;
try {
p =

new (__compilerTemp) T ;

// construct a T at address __compilerTemp
}
catch(...) {

// constructor failed, attention here…

T::operator delete(__compilerTemp, sizeof(T), alloc);
throw;
}

So, quite logically, the compiler automatically inserts code to call the corresponding

T::operator delete for the overloaded

T::operator new if the allocation succeeds but the constructor fails. The "corresponding" signature is

void operator delete(void*,

whatever-parameters-new-takes

) .

Here comes the fly-in-the-ointment part. The C++ Standard (in [C++03] §5.3.4(17)) specifies that the code above will be generated if and only if that overload of

operator delete actually exists. Otherwise, the code does not invoke any

operator delete at all in the case of a constructor failure. In other words: If the constructor fails, memory

will leak. Of six popular compilers tested at the time of this writing, only two issued a warning in such situations.

That's why every overload

void* operator new(

parms

) must be accompanied by its corresponding overload

void operator delete(void*,

parms

) because the compiler wants to call them itself.


/ 521