0

我正在寻找一种A在容器对象中插入多个类型对象的方法,而无需A在插入过程中复制每个对象。一种方法是通过A对容器的引用来传递对象,但不幸的是,据我所知,STL 容器只接受按值传递对象以进行插入(有很多充分的理由)。通常,这不是问题,但在我的情况下,我不希望调用复制构造函数并破坏原始对象,因为A它是 C 库的包装器,其中包含一些指向内部结构的 C 样式指针,它将与原始对象一起被删除...

我只需要一个容器,它可以返回其中一个对象,给定一个特定的索引,并存储在运行时确定的一定数量的项目,所以我想也许我可以编写自己的容器类,但我不知道如何正确地做到这一点。

另一种方法是存储指向A容器内部的指针,但由于我对这个主题没有太多了解,那么在 STL 容器中插入指向对象的指针的正确方法是什么?例如这个:

std::vector<A *> myVector;
for (unsigned int i = 0; i < n; ++i)
{
    A *myObj = new myObj();
    myVector.pushBack(myObj);
}

可能有效,但我不确定如何正确处理它以及如何以干净的方式处理它。我应该仅仅依靠包含 myVector 作为成员的类的析构函数来处理它吗?如果这个析构函数在删除其中一个包含的对象时抛出异常会发生什么?

shared_ptr另外,有些人建议使用or auto_ptror之类的东西unique_ptr,但我对这么多选项感到困惑。哪一个是我的方案的最佳选择?

4

2 回答 2

5

您可以使用booststd reference_wrapper

#include <boost/ref.hpp>
#include <vector>

struct A {};


int main()
{
  A a, b, c, d;
  std::vector< boost::reference_wrapper<A> > v;
  v.push_back(boost::ref(a)); v.push_back(boost::ref(b)); 
  v.push_back(boost::ref(c)); v.push_back(boost::ref(d));
  return 0;
}

使用时需要注意对象的生命周期 reference_wrapper,以免获得悬空引用。

int main()
{
  std::vector< boost::reference_wrapper<A> > v;
  {
    A a, b, c, d;
    v.push_back(boost::ref(a)); v.push_back(boost::ref(b)); 
    v.push_back(boost::ref(c)); v.push_back(boost::ref(d));
    // a, b, c, d get destroyed by the end of the scope
  }
  // now you have a vector full of dangling references, which is a very bad situation
  return 0;
}

如果你需要处理这种情况,你需要一个智能指针。

智能指针也是一种选择,但知道使用哪个是至关重要的。如果您的数据实际上是共享的,shared_ptr请在容器拥有数据时使用 use unique_ptr

无论如何,我看不出包装部分A会发生什么变化。如果它在内部包含指针并遵守三规则,则不会出错。析构函数将负责清理。这是在 C++ 中处理资源的典型方式:在对象初始化时获取它们,在对象的生命周期结束时删除它们。

如果您纯粹想避免构建和删除的开销,您可能需要使用vector::emplace_back.

于 2012-06-19T15:35:05.803 回答
4

在 C++11 中,您可以使用函数就地构造容器元素emplace,从而避免管理指向已分配对象的指针容器的成本和麻烦:

std::vector<A> myVector;
for (unsigned int i = 0; i < n; ++i)
{
    myVector.emplace_back();
}

如果对象的构造函数接受参数,则将它们传递给emplace函数,该函数将转发它们。

但是,对象只能在可复制或可移动的情况下存储在向量中,因为在重新分配向量的存储空间时必须移动它们。您可能会考虑使您的对象可移动,转移托管资源的所有权,或使用类似容器dequelist不会随着对象的增长而移动的容器。

更新:由于这不适用于您的编译器,因此最好的选择可能是std::unique_ptr- 与普通指针相比没有开销,从向量中擦除时会自动删除对象,并允许您将所有权移出向量,如果你要。

如果那不可用,那么std::shared_ptr(或std::tr1::shared_ptrboost::shared_ptr,如果那不可用)也会给你自动删除,以(可能很小)效率成本。

无论您做什么,都不要试图存放std::auto_ptr在标准容器中。它的破坏性复制行为很容易在您不期望的时候意外删除对象。

如果这些都不可用,则使用示例中的指针,并确保在完成对象后记得删除它们。

于 2012-06-19T15:52:01.780 回答