2015-02-01 1 views
0

Я думаю, что этот вопрос может быть дубликат, но я не знаю, как его искать.Может ли оператор new() инициализировать POD перед запуском конструктора?

Я пытаюсь перегрузить operator new, чтобы я мог разрешить буфер переменной длины после моего класса. Мой текущий проект работает по назначению, или это неопределенное поведение?

Если ответ отличается в C++ 98, C++ 03 и C++ 11, пожалуйста, объясните различия.

struct POD { /* ...other POD members here... */ }; 

struct BufferedPOD : POD 
{ 
    size_t n; 
    BufferedPOD() 
    // Assume n is already initialized... 
    { 
    } 

    static void *operator new(size_t size) 
    { 
     return ::operator new(size); 
    } 
    static void *operator new(size_t size, size_t additional_size) 
    { 
     void *const p = operator new(size + additional_size); 
     static_cast<BufferedPOD *>(p)->n = additional_size; 
     return p; 
    } 
    static void operator delete(void *p) 
    { 
     return ::operator delete(p); 
    } 
    static void operator delete(void *p, size_t) 
    { 
     return operator delete(p); 
    } 
}; 

int main() 
{ 
    std::auto_ptr<BufferedPOD> p(new (1000) BufferedPOD()); 
    foo(p.get()); // do something with buffer 
    return 0; 
} 

ответ

1

Во-первых, вы полагаетесь на неопределенное поведение, the memory is indeterminate uponcalling the constructor.

В отладочных сборках он часто заполняется некоторым шаблоном маркера для упрощения отладки, в выпуске эта свобода обычно используется для ускорения строительства.
В обоих случаях чтение неопределенных объектов дает вам UB, однако это будет подробно отображаться.

Во всяком случае, вы собираетесь на это неправильный путь (давайте игнорировать нарушение «правила трех» на данный момент:

Просто объявить соответствующие перегруженные для ::operator new и ::operator delete, и завод-функции (которая должна быть единственным кодом с доступом к только CTOR вы оставляете годными к употреблению), который использует, что и передает экстра-пространство на:?

void* operator new(size_t a, size_t b) { 
    if(a+b< a || a+b < b) 
     throw new std::bad_alloc("::operator new(size_t, size_t) too big"); 
    return operator new(a+b); 
} 
void operator delete(void* p, size_t a, size_t b) {return operator delete(p/*, a+b*/);} 

struct Buffered : POD { // Not a pod due to inheritance 
    Buffered* make(size_t extra) {return new(extra) Buffered(extra);} 
private: 
    size_t n; 
    Buffered(size_t extra) : n(extra) {} 
    Buffered(Buffered&) = delete; 
    void operator=(Buffered&) = delete; 
}; 
+0

Почему вы перемещаете тот оператор нового/удалить за пределами класса особой причиной – Mehrdad

+0

Во-первых, повторное использование. Во-вторых, разрешая удаление с помощью базового указателя, если вы добавляете виртуальный dtor там один раз. В-третьих, избегая кодирования других вариантов. – Deduplicator

+0

Я вижу. +1. Я все еще перевариваю этот ответ, так как я мог бы поклясться, что раньше я пытался идти в аналогичном направлении и ударил камень преткновения, но я не могу понять, что это сейчас ... тем временем, где нарушение правила из 3, о котором вы говорите? – Mehrdad