Эффективный C ++: пункт 52 и как не скрывать все нормальные операторы новых и удаленных версий - PullRequest
4 голосов
/ 13 августа 2010

В конце пункта 52 (Настройка new и delete) в Myer's Effective C ++ он обсуждает, как избежать скрытия обычных новых и удаленных версий при реализации пользовательской версии, следующим образом:

Если вы объявляете любойОператор новостей в классе, вы будете скрывать все эти стандартные формы.Если вы не хотите запретить клиентам этих классов использовать эти формы, обязательно сделайте их доступными в дополнение к новым пользовательским формам, которые вы создаете.Разумеется, для каждого нового оператора, которого вы делаете доступным, не забудьте также удалить соответствующего оператора.Если вы хотите, чтобы эти функции вели себя обычным образом, просто попросите ваши специфичные для класса версии вызывать глобальные версии.

Простой способ сделать это - создать базовый класс, содержащий все обычные формы новых иdelete:

class StandardNewDeleteForms {

public:

  // normal new/delete

  static void* operator new(std::size_t size) throw(std::bad_alloc)

  { return ::operator new(size); }

  static void operator delete(void
*pMemory) throw()

  { ::operator delete(pMemory); }



  // placement new/delete

  static void* operator new(std::size_t size, void *ptr) throw()

  { return ::operator new(size, ptr); }

  static void operator delete(void
*pMemory, void *ptr) throw()

  { return ::operator delete(pMemory, ptr); }



  // nothrow new/delete

  static void* operator new(std::size_t size, const std::nothrow_t& nt) throw()

  { return ::operator new(size, nt); }

  static void operator delete(void
*pMemory, const std::nothrow_t&) throw()

  { ::operator delete(pMemory); }

};

Клиенты, которые хотят дополнить стандартные формы пользовательскими формами, могут просто использовать наследование и использовать объявления (см. пункт 33), чтобы получить стандартные формы:

class Widget: public StandardNewDeleteForms {           // inherit std forms

public:

   using StandardNewDeleteForms::operator new;  // make those

   using StandardNewDeleteForms::operator delete;       // forms visible



   static void* operator new(std::size_t size,          // add a custom

                             std::ostream& logStream)   // placement new

     throw(std::bad_alloc);



   static void operator delete(void
*pMemory,           // add the corres-

                               std::ostream& logStream) // ponding place-

    throw();                                            // ment delete

  ...

};

Зачем беспокоиться о создании класса StandardNewDeleteForms, наследовании от него и затем в производном классе, говоря:

using StandardNewDeleteForms::operator new;
using StandardNewDeleteForms::operator delete;

Не могли бы вы вообще отказаться от базового класса и простонаписать в классе виджетов:

using ::operator new;
using ::operator delete;

чтобы достичь того же?

Ответы [ 3 ]

2 голосов
/ 13 августа 2010

Это было бы фактически бездействующим using. Он просто показывает реализацию базового класса new / delete, которая дублирует нормальное поведение.

Обычно, если вы создаете пользовательские new и delete, вы изменили бы поведение в этом базовом классе, и using ::operator new; больше не будет эквивалентным. Он не делал этого в своем примере, поэтому немного менее понятно, что происходит.

0 голосов
/ 04 мая 2016

Я читаю ту же книгу и удивляюсь точно так же!

Похоже, что правила using зависят от контекста:

При использовании в пространстве имен он позволяет вытягивать членов из других пространств имен, включая глобальное пространство имен, в новое пространство имен ( источник ):

 void f();
 namespace A {
   void g();
 }
 namespace X {
   using ::f;  // global f is now visible as ::X::f
   using A::g; // A::g is now visilbe as ::X::g
 }
 void h()
 {
   X::f(); // calls ::f
   X::g(); // calls A::g
 }

Однако при использовании в определении класса как ( source ):

using nested-name-specifier

тогда

Спецификатор вложенного имени должен называть базовый класс определяемого.

0 голосов
/ 13 августа 2010

Во-первых, нельзя делать using ::operator new;, так как он не является членом родительского класса.

Во-вторых, глобальное новое бесполезно перегружать, потому что большую часть времени: 1. вы будетеиспользовать библиотеки, которые используют или нет этот оператор, внося беспорядок;2. возможно, вы захотите использовать другой код нового / удаления для разных типов объектов;

Идея этого элемента заключается в том, что вы можете изменить поведение нового / удаления классов, которые наследуют родительский класс, что позволяет изменять распределениестратегия для целой группы классов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...