我正在寻找一种方法在容器对象中插入多个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
或auto_ptr
或unique_ptr
等内容,但我对这么多选项感到困惑。哪一个是我的方案的最佳选择?
答案 0 :(得分:5)
您可以使用boost
或std
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
函数,该函数将转发它们。
但是,如果对象是可复制的或可移动的,则只能存储在向量中,因为在重新分配向量的存储时必须移动它们。您可以考虑使对象可移动,转移托管资源的所有权,或者使用deque
或list
之类的容器,这些容器在增长时不会移动对象。
UPDATE:由于这对你的编译器不起作用,最好的选择可能是std::unique_ptr
- 与普通指针相比没有开销,会在擦除时自动删除对象从向量中,如果需要,允许您将所有权移出向量。
如果不可用,那么std::shared_ptr
(或std::tr1::shared_ptr
或boost::shared_ptr
,如果不可用)也会自动删除,以获得(可能很小的)效率成本。
无论您做什么,都不尝试将std::auto_ptr
存储在标准容器中。它具有破坏性的复制行为,可以在您不期望的情况下轻松地意外删除对象。
如果这些都不可用,那么请使用示例中的指针,并确保在完成后删除对象。