存储在向量中的对象的所有权

时间:2012-02-22 17:46:57

标签: c++ memory-management

我想学习C ++,我有一点问题。我有一些Foo类的实例。我有一个vector<Foo> data的FooContainer和一个方法

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

我希望FooContainer成为Foo元素的真正拥护者。我不明白将项目从main传递到Foo的更好方法是什么。

我的主要内容是:

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

通过这种方式,我在main中分配了一个对象,并将副本传递给容器。我将元素存在于2个位置,因此我必须在所有add()之后删除主要元素。

或者最好在main中有一个指针,用new关键字构造项目,并传递指针?这样,Container.data应该是vector<Foo*>

或者,再次将元素放在main中,通过引用添加到容器中,而不是在main中删除它?

我有点困惑。

修改

出于教育目的,我不想使用c ++ 11或提升共享指针:我的想法在指针和引用以及基本的东西上混淆,然后进入高级参数(即使更优雅)我想要清楚我正在做的事情的基础!

4 个答案:

答案 0 :(得分:3)

这一切都取决于你的需要。

如果您的所有实例都是Foo [而不是Foo的子类],则使用vector<Foo>的IMO更简单,因此应该首选。

但是,如果您的某个类Bar扩展为Foo,那么尝试将其添加到vector会导致object slicing,并且您的程序将表现不尽如人意。在这种情况下,您应该更喜欢vector<Foo*>

因此,在我开始时 - 这一切都取决于具体需求,但如果您计划扩展Foo,则必须考虑最后一点。

答案 1 :(得分:2)

您可以将临时传递到容器中;这将在该行的末尾被销毁:

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

在C ++ 11中,您可以直接将其构建到容器中:

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

container.emplace(...);

(我的语法可能不太正确,因为我没有多使用可变参数模板)

在这两种情况下,请记住容器存储Foo类型的对象。您不能存储子类型的对象;如果你尝试,只需复制基类部分就可以“切片”对象。如果你需要存储子类型(正如你的评论暗示的那样),那么你必须存储指针。

  

或者最好在main中有一个指针,使用new关键字构造项目,并传递指针?

这会在从容器中删除对象时产生记住删除对象的复杂性。您可以在C ++ 11中使用vector<unique_ptr<Foo>>,或在C ++ 03中使用boost::ptr_vector<Foo>来处理这个问题。这样做的好处是,您还可以在容器中存储Foo的子类型对象,如果这是您可能想要做的事情。

  

或者,再次将元素放在main中,通过引用添加到容器中,而不是在main中删除它?

您不能将引用放在容器中。你可以在容器中放置指向局部变量的指针,如果非常小心它们在使用时不会被破坏(这很简单,如果所有内容都在main内)。同样,这允许您存储Foo的子类型,而不仅仅是Foo本身。

答案 2 :(得分:2)

我发现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个对象的问题,并且还可以清楚谁拥有新对象。 同样在语义方面,来自boost的API指针容器系列具有比原始指针(IMO)矢量更自然的sytax。

答案 3 :(得分:0)

我认为这不仅仅是所有权问题,而是仅仅是开销问题。

如果每次向对象添加对象时都有vector<foo>,则将值复制到向量。
因此,除了创建要添加到矢量的临时对象,然后删除之外,您还在向量中创建另一个对象,并在那里复制值。

因此,最好只创建一个vector<foo*>来保存对象。

或者更好地使用shared_ptr<foo>vector<shared_ptr<foo>>