2011-04-05 3 views
1

Стандарт говорит, в 5.3.4[expr.new]/7будет ли указатель, возвращаемый новым (size, value) Type [0], легальным и может ли он использоваться для построения массива?

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

и 3.7.3.1[basic.stc.dynamic.allocation]/2

Эффект разыменования указателя возвращается как запрос нулевого размера не определен.

Но если функция распределения определена пользователем, и она знает, что она вернула действительный указатель, было бы еще неопределенным поведение для разыменования? Может ли стандартный мандат неопределенного поведения кода пользователя?

Причина, по которой я прошу, еще одна бессмысленная попытка инициализировать динамический массив объектов нестандартного по умолчанию типа. Какие проблемы у него есть, помимо очевидного отсутствия delete[] и что его можно назвать только с [0]? Я даже правильно использовал aligned_storage?

#include <type_traits> 
#include <stdexcept> 
#include <memory> 
#include <iostream> 

struct T { 
    int val; 
    T() = delete; 
    T(int i) : val(i) {} 
    void* operator new[](std::size_t, std::size_t cnt, const T& t) 
    { 
     typedef std::aligned_storage<sizeof(t), 
        std::alignment_of<T>::value>::type buf; 
     T* ptr = reinterpret_cast<T*>(new buf[cnt]); 
     std::uninitialized_fill_n(ptr, cnt, t); 
     return ptr; 
    } 
}; 

int main() 
{ 
    T* a = new(100, T(7)) T[0]; // using zero is legal per 5.3.4/7 

    std::cout << "a[0] = " << a[0].val << '\n' // but is this legal? 
       << "a[1] = " << a[1].val << '\n' 
       << "a[98] = " << a[98].val << '\n' 
       << "a[99] = " << a[99].val << '\n'; 
    delete[] a; // free the 100 aligned_storages 
} 

испытательный пробег: http://ideone.com/iBW0z

также собирает и работает, как ожидается, с с MSVC++ 2010 EE

+0

«* Причина, я прошу еще один бессмысленный попытка инициализировать динамический массив объектов не по умолчанию, тип конструктивного. * «Почему недостаточно« std :: vector »? Это позволяет именно это. – ildjarn

+0

@ildjarn: для этой цели это более чем достаточно. Я просто изучаю границы языка. – Cubbi

+0

Достаточно справедливо: -] – ildjarn

ответ

3

Там это раздражает логика проблема в вашем коде:

Новое выражение:

T* a = new(100, T(7)) T[0]; 

вызовов T в удаленном конструкторе по умолчанию [expr.new]/17. ;-(

std::vector<T> уверен, хорошо выглядеть примерно сейчас ... :-)

+0

Я вижу, он хочет, чтобы конструктор был доступен. Каждый раз, когда я пытаюсь перехитрить C++, он меня перехитрил. – Cubbi

+2

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

+0

мотивация была попыткой оправдать «новый (...) T [0]», и мотивация для этого была любопытством. – Cubbi

1

только не определено поведение использования в результате reinterpret_cast когда бросок вернемся к первоначальному типу, так что у вас уже есть UB, даже если все остальное в порядке.

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

+0

Хотя все, что я делаю, увеличивает указатель и отбрасывает его в пустоту, я думаю, было бы лучше определить, что он вызвал 'get_temporary_buffer', который возвращает' T * 'вместо того, чтобы вводить массив' aligned_storage '?Сделать его отдельной функцией означает, что я просто реализую вектор, это уже сделано. – Cubbi

 Смежные вопросы

  • Нет связанных вопросов^_^