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

Ownership of objects stored in a vector

本文关键字:对象 所有权 存储      更新时间:2023-10-16

我正在学习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或boost共享指针:我的想法在指针、引用和基本事物上都很困惑,在进入高级争论之前(即使更优雅),我想对我正在做的事情有一个清晰的基础!

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

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

但是,如果您有一个扩展了Foo的类Bar,那么尝试将其添加到vector中将导致对象切片,并且您的程序将无法正常运行。在这种情况下,您应该更喜欢vector<Foo*>

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

我发现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。

您可以将临时文件传递到容器中;这将在线路的最后被销毁:

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本身。

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

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

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

或者最好使用shared_ptr<foo>vector<shared_ptr<foo>>