Можно ли динамически создать массив постоянного размера в C ++? - PullRequest
17 голосов
/ 17 марта 2011

Прежде всего, я хочу заверить вас всех, что задаю этот вопрос из любопытства.Я имею в виду, не говорите мне, что если мне это нужно, то у моего дизайна есть проблемы, потому что мне это не нужно в реальном коде.Надеюсь, я вас убедил :) Теперь к вопросу:

Для большинства типов T мы можем написать

T* p = new T;

, что теперь, если T является типом массива?* Я попробовал это:

typedef int arr[3];
arr* p = new arr;

, но это не работает.

Есть ли допустимый синтаксис для этого или это невозможно в C ++.Если это невозможно, то почему?Спасибо

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

void f(int(&)[3]);
int (*p)[3] = new ???;
f(*p);

Ответы [ 4 ]

11 голосов
/ 17 марта 2011

Чтобы получить указатель на массив из new, необходимо динамически выделить двумерный массив:

int (*p)[3] = new int[1][3];
10 голосов
/ 17 марта 2011

Причина, по которой вы не можете этого сделать, заключается в том, что new int[3] уже выделяет именно то, что вам нужно, объект типа int[3].Просто то, что new-выражение возвращает , является указателем на его первый элемент.5.3.4 / 1:

Если объект не является объектом массива, выражение new возвращает указатель на созданный объект.Если это массив, новое выражение возвращает указатель на начальный элемент массива.

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

Полагаю, что для этого нужно переосмыслить обратно в нужный вам тип указателя (не обязательно переносимый)или выделить структуру, содержащую int[3] (и использовать указатель на его член данных).

[Edit: er, yes или идея FredOverflow, которая не имеет ни недостатка, но требует использования delete[] вместо delete.]

Полагаю, мораль в том, что если вы пишете шаблоны, которые наивно выделяют какой-то неизвестный тип T с помощью new, то шаблон не будет работать, когда кто-то передает массиввведите T.Вы будете назначать его неверному типу указателя, и если вы исправите это (возможно, с помощью auto), вы удалите его неправильно.

Отредактируйте в ответ на вопрос j_kubik:

Вот один из способов различения массивов и не массивов.Если вы напишите такую ​​функцию, которая возвращает объект, который содержит указатель и способен его правильно удалить, то у вас есть универсальный новый / удалить для любого типа 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>();
}
2 голосов
/ 17 марта 2011

Вы всегда можете использовать boost :: array, который будет в C ++ 0x. В противном случае любое решение будет в лучшем случае неудобным: массивы сломан в C, и C ++ поддерживает совместимость с C в этом уважение. Фред Оверлоу предложил одно решение; даже проще (но синтаксически шумно) будет оборачивать массив в структуру: struct A {int arr [3]; }; и распределять и манипулировать этим.

0 голосов
/ 17 марта 2011

Вы просто делаете

int *p = new unsigned int [3]

Затем вы можете использовать *p в качестве указателя или массива, т.е. *(p+1) or p[1]

...