std::vector of objects / pointers / smart pointers to pass objects (buss error: 10)?
我想问一个一般的建议。下面的代码可以完全编译并大致表示我要处理的代码的结构。
简而言之,我想将一系列从基类(Class1)和其他一些参数派生的对象从一个地方传递到另一个地方。更准确地说,实现父类的不同子类,收集它们的实例并传递以进行参数处理。
问题是,您是否建议使用对象向量或指针向量?我不介意从
p / s /在这里UncleBens说,如果抛出异常,使用指针可能会导致内存泄漏。所以也许我真的应该为任务使用智能指针?看起来如何?
p / p / s /很有趣,现实生活中的示例给了我总线错误:10当我尝试使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #include <string> #include <iostream> #include <vector> template<int dim> class Class1 { public: Class1() {}; ~Class1() {}; }; template<int dim> class Class2 : public Class1<dim> { public: Class2() : Class1<dim>() {}; }; template <int dim> class Container { public: Container( Class1<dim> & f, int param1) : c1(f), param_(param1) {} Class1<dim> & c1; int param_; }; static const int d = 2; int main() { int p = 1; Class2<d> c2; std::vector< Container<d> *> p_list; std::vector< Container<d> > list; { p_list.push_back ( new Container<d> ( c2,p ) ); } std::cout<<"from pointers:"<<p_list[0]->param_<<std::endl; { list.push_back( Container<d> ( c2,p ) ); } std::cout<<"from objects:"<<list[0].param_<<std::endl; } |
首先,应该将Class1的析构函数标记为虚,否则,如果派生类(例如Class2)的实例被破坏,则不会正确调用它的析构函数。
对于您的问题,使用对象容器的后果是:
- 容器可能需要制作对象的副本,因此您需要确保有一个副本构造函数(示例中的类将获取由编译器生成的默认类)。复制对象可能会对性能产生影响,因此您需要正确定义副本的语义(是深还是浅,即您是创建class1对象的新副本还是仅复制引用)。
- 您不能具有任何多态性,因此您不能对Container进行子类化,然后将基类和子类的实例放入同一容器中。
- 根据容器的不同,您的对象将在内存中是连续的(向量就是这种情况),这可能会带来性能上的好处。
如果您使用原始指针的容器,则该容器仅需要复制指针(更快),就可以添加包含类型的派生实例。缺点是使用后必须手动销毁对象,而且正如您提到的那样,很容易泄漏内存。
shared_ptrs与原始指针具有类似的优点/缺点,但是关键的好处是,当不再有引用时,shared_ptr会为您销毁对象,这将减少您引入内存泄漏的可能性(但是它当涉及到异常时,\\仍然不是没有可能)。
鉴于您将这些对象移交给进一步处理,我想说一个基于shared_ptr的方法是一个不错的选择。在原始指针之上使用共享ptrs的后果是:
- 可能会有性能开销,因为为了确保线程安全,大多数shared_ptr实现都需要检查/设置锁(这可能涉及对OS的系统调用)。
- 您仍然可以通过在对象之间引入循环引用来泄漏内存。
- 您将必须使用实现C 11的编译器或使用外部库(大多数人使用boost)。
使用shared_ptrs的示例看起来像这样(未经测试)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | #include <string> #include <iostream> #include <vector> template<int dim> class Class1 { public: Class1() {}; virtual ~Class1() {}; }; template<int dim> class Class2 : public Class1<dim> { public: Class2() : Class1<dim>() {}; }; template <int dim> class Container { public: Container( boost::shared_ptr<Class1<dim>> f, int param1) : c1(f), param_(param1) {} boost::shared_ptr<Class1<dim>> c1; int param_; }; static const int d = 2; int main() { int p = 1; boost::shared_ptr<Class1<d>> c2 = boost::make_shared<Class2<d>>(); std::vector<boost::shared_ptr<Container<d>>> list; list.push_back(boost::make_shared<Container<d>>(c2,p)); std::cout <<"from objects:" << list[0]->param_ << std::endl; } |
总而言之,如果接收容器的代码没有在任何地方存储对它们的引用,并且您不需要多态性,那么对象容器就可以了。如果有必要让接收容器的代码将它们存储在某个地方,并且/或者您想要多态容器,请使用共享的ptrs。