Подтвердить что ты не робот

Возможно ли динамическое создание массива постоянного размера в С++?

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

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

T* p = new T;

теперь что, если T - тип массива?

int (*p)[3] =  new ???; //pointer to array of 3 = new ???

Я пробовал это:

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

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

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

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

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

Ответ 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>();
}

Ответ 2

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

int (*p)[3] = new int[1][3];

Ответ 3

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

Ответ 4

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

int *p = new unsigned int [3]

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