Право собственности на объекты, хранящиеся в векторе - PullRequest
2 голосов
/ 22 февраля 2012

Я пытаюсь выучить C ++, и у меня есть небольшая проблема.У меня есть несколько экземпляров класса Foo.И у меня есть FooContainer с vector<Foo> data с методом

void FooContainer::add(Foo item) {
    this->data.push_back(item)
}

Я хочу, чтобы FooContainer был настоящим держателем элементов Foo.Я не понимаю, как лучше передать элементы из main в Foo.

В моем main у меня есть:

Foo item(...);
container.add(item);

Таким образом, у меня есть объект, выделенный в mainи я передаю копию в контейнер.У меня есть элемент, существующий в 2-х местах, поэтому я должен удалить его в главном после всех add().

Или лучше иметь указатель в главном, создать элемент с ключевым словом new и передать указатель?И таким образом Container.data должен быть vector<Foo*>?

Или, опять же, иметь элемент в main, добавить в контейнер по ссылке, а не удалить его в main?

Я немного запутался.

РЕДАКТИРОВАТЬ

в образовательных целях я не хочу использовать c ++ 11 или улучшать общий указатель: мои идеи путаются в указателе, справке и основных вещахПеред тем, как перейти к расширенным аргументам (даже если они более элегантны), я хочу иметь четкую основу того, что я делаю!

Ответы [ 4 ]

3 голосов
/ 22 февраля 2012

Все зависит от ваших потребностей.

Если все ваши экземпляры Foo [и не подкласс Foo], IMO, использующий vector<Foo>, проще и поэтому должен быть предпочтительным.

Однако, если у вас есть класс Bar, который расширяет Foo, попытка добавить его в vector приведет к срезанию объекта , и ваша программа будет работать не так, как ожидалось.В этом случае вы должны предпочесть vector<Foo*>

Итак, как я начал - все зависит от конкретной потребности, но последний момент необходимо учитывать, если вы планируете расширить Foo.

2 голосов
/ 22 февраля 2012

Я считаю, что boost :: ptr_vector действительно хорошо работает для явной семантики владения.

Я использую это так (обратите внимание, что я использую VC9, поэтому я использую std::auto_ptr вместо улучшенного std::unique_ptr):

//use unique_ptr instead if they are supported on your compiler
std::auto_ptr<MyClass> a( new MyClass("a") );
boost::ptr_vector<MyClass> owning_vector;
owning_vector.push_back(a);
// auto_ptr a is now invalid and the ownership of the object is 
// solely with owning_vector

Таким образом, это решило бы вашу проблему создания 2 объектов, а также было бы понятно, кто является владельцем нового объекта.Также с точки зрения семантики семейство API-интерфейсов контейнеров указателей от boost имеет более естественный синтаксис, чем вектор необработанных указателей (IMO).

2 голосов
/ 22 февраля 2012

Вы можете передать временный в контейнер;это будет уничтожено в конце строки:

container.add(Foo(...));

В C ++ 11 вы можете создать его непосредственно в контейнере:

template <typename Args...>
void FooContainer::emplace(Args && a) {
    data.emplace_back(std::forward(a));
}

container.emplace(...);

(Мой синтаксис может не бытьСовершенно верно, поскольку я не очень часто использовал шаблоны с переменными значениями)

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

Или лучше иметь указатель в главном, создать элемент с новымКлючевое слово и передать указатель?

Это создаст сложность запоминания для удаления объекта при удалении его из контейнера.Вы можете использовать vector<unique_ptr<Foo>> в C ++ 11 или boost::ptr_vector<Foo> в C ++ 03, чтобы позаботиться об этом.Это дает преимущество в том, что вы также можете хранить объекты подтипов Foo в контейнере, если вы захотите это сделать.

Или, опять же, добавить элемент в main, добавитьконтейнер по ссылке, а не удалять его в основном?

Нельзя помещать ссылки в контейнеры.Вы можете поместить указатели на локальные переменные в контейнере, если будете очень осторожны, чтобы они не были уничтожены во время использования (что достаточно просто, если все находится внутри main).Опять же, это позволяет вам хранить подтипы Foo, а не только Foo.

0 голосов
/ 22 февраля 2012

Я думаю, это не столько вопрос владения, сколько просто накладные расходы.

Если у вас есть vector<foo>, то каждый раз, когда вы добавляете объект в вектор, он копирует значение в вектор.
Таким образом, помимо создания временного объекта, который нужно добавить в вектор и затем удалить, вы создаете еще один объект в векторе, копируя его значение.

Так что было бы лучше просто создать vector<foo*> для хранения объектов.

Или еще лучше использовать shared_ptr<foo> и vector<shared_ptr<foo>>

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...