2013-03-08 2 views
9

У меня есть программа на C++, где оператор new перегружен. Проблема в том, что , если мое распределение в операторе new терпит неудачу, я все равно вызываю конструктор. Я знаю, что могу избежать этого, бросив std::bad_alloc, но я не хочу этого делать.Как реализовано `new (std :: nothrow)`?

Как я могу сбой в моем перегруженном операторе new и до сих пор не вызывать мой конструктор? По сути, я хочу реализовать что-то вроде new (std::nothrow).

Вот пример, чтобы проиллюстрировать, что я имею в виду. Обратите внимание, что система, которую я тестирую , не имеет защиты памяти. Таким образом, доступ к NULL не делает ничего

Пример 1: перегруженные новый оператор

#include <stdio.h> 
#include <stdlib.h> 
#include <memory> 

class Test { 

public: 

    Test(void) { 
     printf("Test constructor\n"); 
    } 

    void print(void) { 
     printf("this: %p\n", this); 
    } 

    void* operator new(size_t size, unsigned int extra) { 

     void* ptr = malloc(size + extra); 
     ptr = NULL; // For testing purposes 
     if (ptr == NULL) { 
      // ? 
     } 
     return ptr; 
    } 
}; 

int main(void) { 

    Test* t = new (1) Test;    
    t->print(); 
    printf("t: %p\n", t); 

    return 0; 
} 

выводе для этого:

$ ./a.out 
Test constructor 
this: 00000000 
t: 00000000 

Очевидно, что constrcutor становится вызывается, когда new не удалось.

Пример 2: декларация Огромный класса с новым (станд :: nothrow)

#include <stdio.h> 
#include <stdlib.h> 
#include <memory> 

class Test { 

    int x0[0x0fffffff]; 
    int x1[0x0fffffff]; 
    int x2[0x0fffffff]; 
    int x3[0x0fffffff]; 
    int x4[0x0fffffff]; 
    int x5[0x0fffffff]; 
    int x6[0x0fffffff]; 
    int x7[0x0fffffff]; 
    int x8[0x0fffffff]; 
    int x9[0x0fffffff]; 
    int xa[0x0fffffff]; 
    int xb[0x0fffffff]; 
    int xc[0x0fffffff]; 
    int xd[0x0fffffff]; 
    int xe[0x0fffffff]; 
    int xf[0x0fffffff]; 

public: 

    Test(void) { 
     printf("Test constructor\n"); 
    } 

    void print(void) { 
     printf("this: %p\n", this); 
    } 
}; 

int main(void) { 

    Test* t = new (std::nothrow) Test;  
    t->print(); 
    printf("t: %p\n", t); 

    return 0; 
} 

выводом для этого:

this: 00000000 
t: 00000000  

Очевидно, что constrcutor является не вызывалась когда new не удалось.

Как я могу реализовать new (std::nothrow) вид функциональности в моем перегружен new оператор?

ответ

9

ли компилятор проверяет для нулевого указателя после вызова operator new или нет, перед вызовом деструктора, зависит от того, имеет ли функции Распределителя не-метание исключения спецификации или нет. Если нет, компилятор предполагает, что operator new будет выдавать, если память отсутствует. В противном случае предполагает, что operator new вернет нулевой указатель. В вашем случае, ваш operator new должно быть:

void* operator new(size_t size, unsigned int extra) throw() 
{ 
    //... 
} 

или если вы можете рассчитывать на 11 поддержку C++:

void* operator new(size_t size, unsigned int extra) noexcept 
{ 
} 
+0

Спасибо большое, я никогда бы не догадался ответ. Вопрос, независимо от того, что вы сказали, документирован ли он где-либо в стандарте C++ 2003? – tinkerbeast

+1

§5.3.4/13: «Если функция распределения возвращает значение null, то инициализация не должна выполняться, функция деаллокации не должна вызываться, а значение нового выражения должно быть null». –

+1

На самом деле, как в C++ 11, так и в C++ 03, поведение задается в '[basic.stc.dynamic.allocation]/3'.Для C++ 11 формулировка такова: «Если функция распределения, объявленная с не-бросающей спецификацией исключений, не может выделить хранилище, она должна вернуть нулевой указатель. Любая другая функция распределения, которая не может распределить память, должна указывать на ошибку только выбрасывая исключение типа, который будет соответствовать обработчику типа std :: bad_alloc. " Текст C++ 03 очень похож. – Mankarse