Пустой динамический массив в c ++ - PullRequest
1 голос
/ 30 марта 2011

Допустим, у меня есть объект с именем Square с конструктором Square(int rx, int ry), я хочу создать динамический массив квадратов с различными аргументами в конструкторе:

Square *squares = new Square[10];  
for (int i = 0; i < 10; i++)
{
     squares[i] = new Square(i, i);
}

Однако это не удается,говоря нет подходящего конструктора по умолчанию, доступного .Итак, как мне создать пустой или NULL массив, а затем сделать конструкции позже ?

РЕДАКТИРОВАТЬ: Это должен быть массив, из-за других вещей в коде,трудно объяснить здесь.

Ответы [ 9 ]

7 голосов
/ 30 марта 2011

Используйте vector. У него нет этой проблемы, пока Square копируется.

vector<Square> squares;
for (int i = 0; i < 10; i++)
{
     squares.push_back(Square(i, i));
}
5 голосов
/ 30 марта 2011

Вы можете создать массив из указателей * от 1002 * до Square:

Square **squares = new Square*[10];

for (int i = 0; i < 10; i++)
{
     squares[i] = new Square(i, i);
}

Как уже отмечали другие, рекомендуется вместо этого использовать std::vector.

1 голос
/ 30 марта 2011

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

Однако отсутствующий конструктор, на который ссылается сообщение об ошибке, это конструктор Square.Вам нужно добавить конструктор для Square, который не принимает аргументов. ONE из следующего будет делать:

class Square {
    Square() { ... }
    // Square with dimensions of 0 is empty
    Square(int length=0, int width=0) { ... }
    ...
};

Обратите внимание, что если вы поместите оба этих файла в файл, вы получите ошибку, потому что это будет невозможнознать, какой конструктор вызывать, если не задано никаких аргументов .

Возможно, вам понадобится конструктор по умолчанию, даже если вы используете std::vector.«Вероятно», потому что вы можете обойти это, если вы ограничите себя конструкторами std::vector, которые берут объект, например ::

std::vector<Square> foo(10, Square(0, 0));
// reassign each element accordingly

Я уже добавил это каккомментарий к самому вопросу.Как говорит Херб Саттер, std::vector предназначен для взаимозаменяемости с массивами :

Почему так важно, чтобы векторы были смежными?Потому что это то, что вам нужно, чтобы гарантировать, что вектор совместим с макетом с массивом C, и поэтому у нас нет оснований не использовать вектор в качестве превосходной и безопасной для типов альтернативы массивам, даже когда нам нужно обмениваться данными с кодом C.Таким образом, вектор является нашим входом в другие языки и большинство функций операционных систем, языком которых является почтенный массив C.

Синтаксис, кстати, таков (если v - вектор) &v[0].То есть, взять адрес первого элемента (и это ссылка, так что он работает на всех std::vector с, кроме std::vector<bool>), и вы получите указатель, который вы можете передать любой функции, которая ожидает указатель (Вы можете, конечно, получить длину «массива» как v.size()).

1 голос
/ 30 марта 2011

Используйте vector в программах, где это применимо.Если вам действительно нужно использовать необработанный new, вы можете использовать новое размещение.

Square *squares = static_cast<Square*>(operator new(sizeof(*squares) * 10));
for (int i = 0; i < 10; i++) {
  new (static_cast<void*>(squares + i)) Square(i, i);
}

И удалите его с помощью operator delete(squares);.Обратите внимание, что вам нужно вручную вызывать деструкторы этих объектов.Кроме того, вы можете создавать объекты с помощью итератора необработанного хранилища

std::raw_storage_iterator<Square*, Square> rsi(squares);
for (int i = 0; i < 10; i++) {
  *rsi++ = Square(i, i);
}

. Конечно, необходимость вручную вызывать деструкторы в конце использования остается.

1 голос
/ 30 марта 2011

Стандартные библиотечные контейнеры делают это с помощью размещения new. Использование стандартного контейнера библиотеки, такого как std::vector, безусловно, самый простой способ. И размещение новых труднее всего. Выделение отдельных объектов и сохранение указателей в массиве, как упоминал Xeo, находится посередине.

1 голос
/ 30 марта 2011

Вы должны сделать массив указателей на SQuare.

Однако я бы также рекомендовал использовать std::vector вместо "классического" массива, это хорошее решение, если Square копируемый.

Однако, если это не так, или если вы все еще решаете пойти по указателю, установите std::vector из shared_ptr, чтобы оставить всю нагрузку на удаление компилятору.

Это даст что-то вроде:

#include <vector>
#include <boost/shared_ptr.hpp> //on some compilers, you can use #include <memory> instead

using std::vector;
using boost::shared_ptr; // or using std::shared_ptr

vector<shared_ptr<Square> > squares(10);

for (int i = 0; i < 10; i++)
{
     squares[i].reset(new Square(i, i));
}

Чтобы пойти еще дальше, вы можете взглянуть на библиотеку Boost Pointer Container .

0 голосов
/ 30 марта 2011
Square *squares = new Square[10];

Эта операция вызывает конструктор по умолчанию 10 раз. И нет ни одной ошибки в вашем фрагменте. Итак, предоставьте один. Просто напишите метод установки для инициализации членов класса.

for (int i = 0; i < 10; i++)
{
     squares[i] = new Square(i, i);
}

С помощью операции new снова в цикле for вы просто теряете память, полученную ранее, но делаете то, что думаете.

Также не забудьте позвонить delete[] на squares.

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

Используйте std::vector или используйте ту же технику, что и в этом: выделите «сырое» пространство памяти с глобальным оператором new, и создайте объекты в этом хранилище, используя размещение new (и уничтожьте их, вызывая dtor напрямую вместо использования delete.

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

Простое использование указателя на указатель

Square **squares = new Square*[10];  

И это должно работать. Но я думаю, что вам действительно лучше, когда вы начнете использовать контейнеры STL, такие как vector

...