Перегрузка глобальных новых и удаление безопасно - PullRequest
2 голосов
/ 18 марта 2011

Читая Брюса Экеля, я наткнулся на следующий пример:

#include <cstdio>
#include <cstdlib>
using namespace std;
void* operator new(size_t sz) 
{
  printf("operator new: %d Bytes\n", sz);
  void* m = malloc(sz);
  if(!m) puts("out of memory");
   return m;
}

void operator delete(void* m) 
{
 puts("operator delete");
 free(m);
}
 class S {
 int i[100];
 public:
 S() { puts("S::S()"); }
 ~S() { puts("S::~S()"); }
 };

int main() {
puts("creating & destroying an int");
int* p = new int(47);
delete p;
puts("creating & destroying an s");
S* s = new S;
delete s;
puts("creating & destroying S[3]");
S* sa = new S[3];
delete []sa;
} 

У меня есть сомнения со следующим утверждением:

  1. Обратите внимание, что printf( ) и puts( ) используются вместо iostreams. Это происходит потому, что когда создается объект iostream (например, глобальные cin, cout и cerr), он вызывает operator new для выделения памяти. С printf( ) вы не попадаете в тупик, потому что он не вызывает new для инициализации.
    Однако, когда я запускаю программу после замены put на cout, я не получаю такой тупик. Кто-нибудь может это объяснить?

  2. operator new возвращает пустой указатель, но в итоге мы получаем указатель на динамически размещенный объект. Так это конструктор, который возвращает указатель на объект (это, хотя конструктор не имеет возвращаемого типа) или его компилятор, который делает меня внутренне?

Ответы [ 2 ]

2 голосов
/ 18 марта 2011

1) Стандарт C ++ содержит много «mays», которые обычно не используются. Это одна из них. Оператор << function <strong>может использовать динамическую память, но это не обязательно. Часто это не так.

То, что ваш пример работает, не означает, что он правильный. Это просто означает, что он работает с реализацией, которую вы используете. На других реализациях он может сломаться.

«Маи», определенные стандартом, могут также идти в другом направлении. Например, любой заголовок STL может включать в себя любой другой стандартный заголовок, но это не требуется. Это часто имеет место с заголовком iostream и заголовками istream и ostream. Практически любая реализация включает в себя ostream и istream при использовании iostream, но технически это не обязательно. Это означает, что когда вы используете ostream и просто включаете iostream, ваша программа может работать, но на самом деле это не правильно в отношении стандарта.

Для c и c ++ довольно важно знать, что может молча сломаться, но это часто не очень легко.

1 голос
/ 18 марта 2011
  1. Использование printf() во избежание рекурсивного вызова в operator new() - это мера безопасности - просто чтобы убедиться, что она работает.Откуда вы знаете, что использование iostream никогда не вызывает функцию operator new()?

  2. Вы путаете новое выражение (языковая конструкция) сoperator new() функция. новое выражение действительно возвращает типизированный указатель, но вызов функции operator new() выполняется "под капотом", а функция operator new() возвращает void*.Для этого компилятор генерирует весь необходимый код.

...