1) std::vector
std::vector
действительно является правильным способом сделать это в C ++.
std::vector<Bullet> bullets;
bullets.reserve(10); // allocate memory for bullets without constructing any
bullets.push_back(Bullet(10.2,"Bang")); // put a Bullet in the vector.
bullets.emplace_back(10.2,"Bang"); // (C++11 only) construct a Bullet in the vector without copying.
2) оператор new []
Это также можно сделать с помощью new
, но на самом деле этого не следует делать. Ручное управление ресурсами с помощью _6 _ / _ 7_ - сложная задача, аналогичная метапрограммированию шаблонов в том смысле, что ее лучше оставить разработчикам библиотек, которые будут использовать эти функции для создания эффективных высокоуровневых библиотек для вас. Фактически, чтобы сделать это правильно, вы в основном реализуете внутреннюю часть std::vector
.
Когда вы используете оператор new
для выделения массива, каждый элемент в массиве инициализируется по умолчанию. Ваш код мог бы работать, если бы вы добавили конструктор по умолчанию в Bullet
:
class Bullet {
public:
Bullet() {} // default constructor
Bullet(double,std::string const &) {}
};
std::unique_ptr<Bullet[]> b = new Bullet[10]; // default construct 10 bullets
Затем, когда у вас есть реальные данные для Bullet
, вы можете назначить их одному из элементов массива:
b[3] = Bullet(20.3,"Bang");
Обратите внимание на использование unique_ptr
, чтобы обеспечить правильную очистку и безопасность в исключительных случаях. Выполнение этих действий вручную сложно и подвержено ошибкам.
3) operator new
Оператор new
инициализирует свои объекты в дополнение к выделению для них места. Если вы хотите просто выделить место, вы можете использовать operator new
.
std::unique_ptr<Bullet,void(*)(Bullet*)> bullets(
static_cast<Bullet*>(::operator new(10 * sizeof(Bullet))),
[](Bullet *b){::operator delete(b);});
(Обратите внимание, что unique_ptr
гарантирует, что хранилище будет освобождено, но не более того. В частности, если мы создаем какие-либо объекты в этом хранилище, мы должны вручную уничтожить их и сделать это безопасным способом.)
bullets
теперь указывает на хранилище, достаточное для массива Bullet
s. В этом хранилище можно построить массив:
new (bullets.get()) Bullet[10];
Однако конструкция массива снова использует инициализацию по умолчанию для каждого элемента, чего мы пытаемся избежать.
AFAIK C ++ не определяет какой-либо четко определенный метод построения массива без создания элементов. Я полагаю, что это во многом связано с тем, что это было бы недопустимо для большинства (всех?) Реализаций C ++. Итак, хотя следующее технически не определено, на практике оно довольно хорошо определено.
bool constructed[10] = {}; // a place to mark which elements are constructed
// construct some elements of the array
for(int i=0;i<10;i+=2) {
try {
// pretend bullets points to the first element of a valid array. Otherwise 'bullets.get()+i' is undefined
new (bullets.get()+i) Bullet(10.2,"Bang");
constructed = true;
} catch(...) {}
}
Это создаст элементы массива без использования конструктора по умолчанию. Вам не нужно создавать все элементы, только те, которые вы хотите использовать. Однако, уничтожая элементы, вы должны не забывать уничтожать только те элементы, которые были созданы.
// destruct the elements of the array that we constructed before
for(int i=0;i<10;++i) {
if(constructed[i]) {
bullets[i].~Bullet();
}
}
// unique_ptr destructor will take care of deallocating the storage
Вышеупомянутое - довольно простой случай. Сложнее сделать нетривиальное использование исключений этого метода безопасным, не заключая все это в класс. Обобщение этого класса в основном означает реализацию std::vector
.
4) std::vector
Так что просто используйте std::vector
.
person
bames53
schedule
14.03.2012
Bullet
, вашBullet*
не будет указывать наBullet
. - person David Schwartz   schedule 14.03.2012