将对象引用存储在一个简单的容器中

时间:2012-06-19 15:29:52

标签: c++ pointers stl reference containers

我正在寻找一种方法在容器对象中插入多个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_ptrauto_ptrunique_ptr等内容,但我对这么多选项感到困惑。哪一个是我的方案的最佳选择?

2 个答案:

答案 0 :(得分: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如果容器拥有使用unique_ptr的数据。

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

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

答案 1 :(得分:4)

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

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

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

但是,如果对象是可复制的或可移动的,则只能存储在向量中,因为在重新分配向量的存储时必须移动它们。您可以考虑使对象可移动,转移托管资源的所有权,或者使用dequelist之类的容器,这些容器在增长时不会移动对象。

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

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

无论您做什么,都不尝试将std::auto_ptr存储在标准容器中。它具有破坏性的复制行为,可以在您不期望的情况下轻松地意外删除对象。

如果这些都不可用,那么请使用示例中的指针,并确保在完成后删除对象。