Ответ 1
Причина, по которой вы не можете этого сделать, заключается в том, что new int[3]
уже выделяет именно то, что вы хотите, объект типа int[3]
. Это то, что возвращает новое выражение, является указателем на его первый элемент. 5.3.4/1:
Если объект является объектом без массива, новое выражение возвращает указатель к созданному объекту. Если это массив, новое выражение возвращает указатель на исходный элемент массив.
Возврат указателя к первому элементу - это то, что позволяет 3
быть неизвестным до выполнения, поэтому я предполагаю, что, зная его заранее, вы преодолели гибкость, которую вы не используете.
Я предполагаю, что пути вокруг этого - reinterpret_cast обратно к типу указателя, который вы хотите (не обязательно переносимый), или выделить структуру, содержащую int[3]
(и использовать указатель на свой элемент данных).
[Edit: er, yeah или FredOverflow идея, которая не имеет недостатков, но требует delete[]
вместо delete
.]
Я думаю, что мораль - это, если вы пишете шаблоны, которые наивно выделяют неизвестный тип T
с помощью new
, тогда шаблон не будет работать, если кто-то передает тип массива как T
. Вы будете назначать его неправильному типу указателя, и если вы исправите это (возможно, с помощью auto
), вы будете ошибочно ошибаться.
Изменить в ответ на вопрос j_kubik:
Здесь один способ различать типы массива и не-массива. Если вы пишете такую функцию, которая возвращает объект, содержащий указатель и способный правильно удалить его, тогда у вас есть общий новый /delete для любого типа T.
#include <iostream>
template <typename T>
void make_thing_helper(T *) {
std::cout << "plain version\n";
}
template <typename T, int N>
void make_thing_helper(T (*)[N]) {
std::cout << "array version\n";
}
template <typename T>
void make_thing() {
make_thing_helper((T*)0);
}
int main() {
typedef int T1;
typedef int T2[3];
make_thing<T1>();
make_thing<T2>();
}