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 them you usually don't want to hide the built-in signatures.

In C++, after you define a name in a scope (e.g., in a class scope), it will hide the same name in all enclosing scopes (e.g., in base classes or enclosing namespaces), and overloading never happens across scopes. And when said name is

operator new , you need to be extra cautious lest you make life hard for your class's clients.

Say you define a class-specific

operator new :

class C {

// …

static void* operator new(size_t, MemoryPool&);

// hides three normal forms
};

Then, if someone tries to write an expression as boring as plain old

new C , the compiler will reject it on grounds that it can't find plain old

operator new . Declaring the

C::operator new overload that takes a

MemoryPool hides all other overloads, including the familiar built-in global versions that we all know and love, to wit:

void* operator new(std::size_t);

// plain new
void* operator new(std::size_t, std::nothrow_t) throw();

// nothrow new
void* operator new(std::size_t, void*);

// in-place new

Alternatively, perhaps your class provides a class-specific version of one of these three operators

new . In that case, by declaring one of them your class will by default also mask the other two:

class C {

// …

static void* operator new(size_t, void*);

// hides other two normal forms
};

Prefer to have class

C explicitly bring into scope all three of the standard variants of

operator new . Normally, all should have the same visibility. (The visibility can still be made

private for individual forms, such as if you want to explicitly disable the plain or non-throwing

operator new , but the purpose of this Item is to remind you not to hide them inadvertently.)

Note that you should always avoid hiding in-place

new because STL containers use it extensively.

The only remaining trick is that exposing the hidden operators

new needs to be done in two different ways in two different circumstances. If your class's base class also defines

operator new , all you need to do to "unhide"

operator new is:

class C : public B {

// …
public:

using B::operator new;
};

Otherwise, if there is no base class version or the base class doesn't define

operator new , you will need to write some short forwarding functions (because you can't employ

using to pull names from the global namespace):

class C {

// …
public:
static void* operator new(std::size_t s) {
return ::operator new(s);
}
static void* operator new(std::size_t s, std::nothrow_t nt) throw() {
return ::operator new(s, nt);
}
static void* operator new(std::size_t s, void* p) {
return ::operator new(s, p);
}
};

The advice above also applies to the array forms of

operator new[] and

operator delete[] .

Avoid calling the

new (nothrow) version in client code, but provide it to save some clients from surprises if they happen to use it.


/ 521