C++: типы массивов и новое

Я изучаю С++. Следующая программа выглядит красиво и универсально:

typedef some_type T;
int main() {
  T* p = new T;
}

И это действительно работает для типов, не являющихся массивами, таких как int и т. д. Однако, если я попробую typedef int T[2];, он сломается с ошибкой:

невозможно преобразовать 'int*' в 'int (*)[2]'.

Какая здесь логика? Могу ли я что-нибудь сделать, чтобы new возвращал объект правильного (для этого указателя) типа?

typedef int T[2];
int main() {
  T* p = new ???;
}

Кстати, new int[2] тоже не работает. Возможно, мне здесь не хватает какого-то синтаксиса, общая идея заключалась бы в том, чтобы выделить объект типа T, где тип T представляет собой массив из двух целых чисел.

T* на самом деле int(*)[2]. Таким образом, правильный синтаксис будет T* p = new T[2]; .
user12002570 21.07.2024 16:25

Примечание: обычно лучше использовать std::array для необработанного массива C. Создание псевдонимов типов также проще.

wohlstad 21.07.2024 16:26

Могу ли я что-нибудь сделать с new, чтобы он возвращал объект правильного (для этого указателя) типа? Ответ: T* p = new int[1][2];

Matt 21.07.2024 16:33

Или, если вы не знаете размер до момента выполнения (скажем, размер зависит от данных, считываемых во время работы программы), используйте контейнер с изменяемым размером, например std::vector. По сути, лучше избегать массивов в стиле C (и прямого использования любого выражения new).

Peter 21.07.2024 16:37

Лучше использовать интеллектуальные указатели и массив или вектор вместо указателя и массива в стиле C, потому что вам нужно позаботиться об управлении памятью.

Mahdy.n 21.07.2024 17:43

@Mahdy.n даже с умными указателями вы должны использовать правильный синтаксис для new. И vector здесь неуместно, поскольку им нужен только один экземпляр T.

Mark Ransom 21.07.2024 18:10

@MarkRansom конечно, но если он использует указатель на vector с unique_ptr<vector<int>> или array, то ему не нужно использовать new и delete.

Mahdy.n 21.07.2024 18:46

@Mahdy.n как инициализировать unique_ptr без new? Это была моя точка зрения.

Mark Ransom 21.07.2024 19:57

@MarkRansom У меня, конечно, не так много опыта разработки, как у тебя, но стоит ли нам использовать NEW? Я так не думаю, мы можем создать уникальный указатель на вектор, например: using T = int; для любого типа данных и std:: vector<T> vec(size); и указатель ` auto vec_ptr = std::make_unique<std::vector<T>>(vec);` и чем использовать указатель.

Mahdy.n 21.07.2024 21:45

@MarkRansom, ты прав, даже с unique_ptr где-то прячется new. Но (1) вы можете использовать make_unique, чтобы полностью очистить свой код от явных new (2) вам не нужно беспокоиться о ручных delete. Может быть, я неправильно понял твое намерение, но ты не согласен, что так все же лучше?

wohlstad 22.07.2024 06:45

@wohlstad да, я согласен, что исключение нового/удаления - это хорошо, локальная переменная - лучшее, если вам это сойдет с рук. Но поскольку речь идет о new, весь этот побочный стеб просто отвлекает.

Mark Ransom 22.07.2024 14:00

@MarkRansom, поскольку ОП упомянул, что они изучают C++, я подумал, что это может быть полезно (помимо решения конкретной проблемы). Как вы сказали, локальная переменная была бы лучше, если бы она применима, и я также упомянул об этом в своем ответе ниже.

wohlstad 22.07.2024 14:04
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
12
104
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Возможно, мне не хватает синтаксиса здесь

Прежде всего обратите внимание, что T* на самом деле является int(*)[2].

Теперь здесь есть два варианта/ответа:

Один допустимый синтаксис:

T* p = new int[2][2];

Или другой эквивалентный допустимый синтаксис:

T* p = new T[2]; //this is also valid in c++

Кстати, вам следует использовать std::array и умные указатели в современном C++.

Другой ответ уже дал решение вашей насущной проблемы.

Но поскольку вы упомянули, что изучаете C++, ниже вы можете найти несколько рекомендаций:

  • Как уже упоминалось, рекомендуется отдавать предпочтение std::array необработанным массивам C (или std::vector для массивов динамического размера).

  • Используйте указатели только в том случае, если они вам действительно нужны. Во многих случаях лучше использовать объекты «по значению» (и это должно быть по умолчанию).

  • Если вам необходимо использовать указатель, отдайте предпочтение умным указателям вместо необработанных указателей C. Они будут автоматически управлять сроком существования объекта (когда вы используете new, вы должны не забыть сопоставить его с delete).

Вот краткий пример:

#include <memory>
#include <array>

// T is an alias for the type of std::array<int,2>:
using T = std::array<int,2>;    

int main() {
    // a is an object of type std::array<int,2>:
    T a;    

    // p is a unique_ptr to std::array<int,2>:
    std::unique_ptr<T> p = std::make_unique<T>();   
}

Обратите внимание на использование псевдонима типа вместо typedef в современном C++.

Другие вопросы по теме