Различия между новыми char [n] и новыми (char [n])
Есть ли разница между new char[n]
и new (char[n])
?
У меня есть второй случай в сгенерированном коде, g++ (4.8.0) дает мне
ISO C++ does not support variable-length array types [-Wvla]
Это заставляет меня думать, являются ли эти два одинаковыми или нет.
-
new char[n]
означает "выделить n
объекты типа char
.
- означает
new (char[n])
означает "выделить 1 объект типа array of n chars
"?
- Удаление первого ясно.
- Я должен удалить второй с помощью
delete
или delete[]
?
- Есть ли какие-либо другие различия, о которых я должен знать?
- Могу ли я безопасно удалить круглые скобки и перевести второй случай в первый, когда другие части программного обеспечения ожидают второй?
Код генерируется сторонним программным обеспечением (и используется другими частями программного обеспечения), поэтому я не могу просто "использовать вектор вместо".
Это минимальный пример:
int main (void)
{
int n(10);
int *arr = new (int[n]); // removing parentheses fixes warning
*arr = 0; // no "unused variable" warning
return 0;
}
Ответы
Ответ 1
Основная проблема здесь в том, что С++ не разрешает использовать массив [n]
в типе, если n
не является постоянным выражением. g++ и некоторые другие компиляторы иногда позволят это, но невозможно добиться последовательного поведения при запуске смешивания массивов переменной длины и шаблонов.
Явное исключение int* p = new int[n];
работает, потому что здесь [n]
является синтаксически частью выражения new
, а не частью типа, предоставленного new
, а new
выполняет "know how" для создания массивов с длиной, определенной во время выполнения.
// can be "constexpr" in C++11:
const int C = 12;
int main() {
int* p1 = new int[C];
int* p2 = new (int[C]);
typedef int arrtype[C];
int* p3 = new arrtype;
int n = 10;
int* p4 = new int[n];
// int* p5 = new (int[n]); // Illegal!
// typedef int arrtype2[n]; // Illegal!
// int* p6 = new arrtype2;
delete[] p1;
delete[] p2;
delete[] p3;
delete[] p4;
}
Семантически, однако, после того, как какой-либо окончательный [C]
используется для преобразования типа в тип массива, новое выражение только заботится о том, имеет ли он дело с массивом или нет. Все требования о типе выражения, использовать ли new[]
и delete[]
и т.д., Говорят о таких вещах, как "когда выделенным типом является массив", а не "когда используется новый синтаксис массива". Таким образом, в приведенном выше примере инициализации p1
, p2
и p3
эквивалентны, и во всех случаях delete[]
является правильной формой освобождения.
Инициализация p4
действительна, но код для p5
и p6
неверен С++. g++ позволял бы им в любом случае, если не использовать -pedantic
, и по аналогии ожидаю, что инициализации для p4
, p5
и p6
также будут эквивалентными. Разборка @MM поддерживает этот вывод.
Итак, да, это должно быть безопасное улучшение, чтобы удалить "лишние" круглые скобки из этого выражения. Правильное удаление - это тип delete[]
.
Ответ 2
Эффект тот же (и оба выражения дают T *
, который указывает на первый элемент массива и его нужно удалить с помощью delete[]
(см. 5.3.4/5), но ясно T[N]
должен быть допустимым типом в последнем случае, поэтому N
должно быть константным выражением, в то время как в первом случае это динамический аргумент нового выражения array.
Ответ 3
new int [n]
//Allocates memory for `n` x `sizeof(int)` and returns
//the pointer which points to the beginning of it.
+-----+-----+-----+-----+-----+-----+-----+-----+------+------+
| | | | | | | | | | |
| | | | | | | | | | |
| | | | | | | | | | |
+-----+-----+-----+-----+-----+-----+-----+-----+------+------+
new (int [n])
//Allocate a (int[n]), a square which its item is an array
+----------------------------------------------------------------+
|+-----+-----+-----+-----+-----+-----+-----+-----+------+------+ |
|| | | | | | | | | | | |
|| | | | | | | | | | | |
|| | | | | | | | | | | |
|+-----+-----+-----+-----+-----+-----+-----+-----+------+------+ |
+----------------------------------------------------------------+
Фактически оба они равны.
Вот код, сгенерированный ассемблером (просто незначащее различие):
int n = 10;
int *i = new (int[n]);
int *j = new int[n];
i[1] = 123;
j[1] = 123;
----------------------------------
! int *i = new (int[n]);
main()+22: mov 0x1c(%esp),%eax
main()+26: sub $0x1,%eax
main()+29: add $0x1,%eax
main()+32: shl $0x2,%eax
main()+35: mov %eax,(%esp)
main()+38: call 0x401620 <_Znaj> // void* operator new[](unsigned int);
main()+43: mov %eax,0x18(%esp)
! int *j = new int[n];
main()+47: mov 0x1c(%esp),%eax
main()+51: shl $0x2,%eax
main()+54: mov %eax,(%esp)
main()+57: call 0x401620 <_Znaj> // void* operator new[](unsigned int);
main()+62: mov %eax,0x14(%esp)
!
! i[1] = 123;
main()+66: mov 0x18(%esp),%eax
main()+70: add $0x4,%eax
main()+73: movl $0x7b,(%eax)
! j[1] = 123;
main()+79: mov 0x14(%esp),%eax
main()+83: add $0x4,%eax
main()+86: movl $0x7b,(%eax)
Вы должны delete
оба из них delete [] ...