使用shared_ptr的例子?
嗨,我今天问了一个问题, 如何在同一个向量数组中插入不同types的对象 ,我的代码在这个问题是
gate* G[1000]; G[0] = new ANDgate() ; G[1] = new ORgate; //gate is a class inherited by ANDgate and ORgate classes class gate { ..... ...... virtual void Run() { //A virtual function } }; class ANDgate :public gate {..... ....... void Run() { //AND version of Run } }; class ORgate :public gate {..... ....... void Run() { //OR version of Run } }; //Running the simulator using overloading concept for(...;...;..) { G[i]->Run() ; //will run perfectly the right Run for the right Gate type }
我想用vector,所以有人写我应该这样做:
std::vector<gate*> G; G.push_back(new ANDgate); G.push_back(new ORgate); for(unsigned i=0;i<G.size();++i) { G[i]->Run(); }
但随后他和其他人build议我最好使用Boost指针容器
或者shared_ptr
。 我花了最近3个小时阅读这个话题,但文件似乎相当先进。 ****任何人都可以给我一个shared_ptr
用法的小代码示例,为什么他们build议使用shared_ptr
。 还有其他types,如ptr_vector
, ptr_list
和ptr_deque
** **
编辑1:我也读过一个代码示例,其中包括:
typedef boost::shared_ptr<Foo> FooPtr; ....... int main() { std::vector<FooPtr> foo_vector; ........ FooPtr foo_ptr( new Foo( 2 ) ); foo_vector.push_back( foo_ptr ); ........... }
而我不明白的语法!
使用shared_ptr
vector
可以消除内存泄漏的可能性,因为您忘记了在每个元素上遍历向量并调用delete
。 让我们一行一行地稍微修改一下示例。
typedef boost::shared_ptr<gate> gate_ptr;
为共享指针types创build一个别名。 这样可以避免inputstd::vector<boost::shared_ptr<gate> >
导致的C ++语言中的丑陋,并忘记closures大于号的间隔。
std::vector<gate_ptr> vec;
创buildboost::shared_ptr<gate>
对象的空向量。
gate_ptr ptr(new ANDgate);
分配一个新的ANDgate
实例并将其存储到shared_ptr
。 分开这样做的原因是为了防止操作抛出时可能发生的问题。 在这个例子中这是不可能的。 Boost shared_ptr
“最佳实践”解释了为什么分配到一个独立的对象而不是暂时的最佳实践 。
vec.push_back(ptr);
这将在向量中创build一个新的共享指针,并将ptr
复制到其中。 shared_ptr
的内容中的引用计数确保了ptr
中的分配对象被安全地转移到向量中。
没有解释的是shared_ptr<gate>
的析构函数确保分配的内存被删除。 这是避免内存泄漏的地方。 std::vector<T>
的析构函数确保为vector中的每个元素调用T
的析构函数。 但是,指针的析构函数(例如, gate*
) 不会删除已分配的内存 。 这就是你想通过使用shared_ptr
或ptr_vector
来避免的。
我将添加关于shared_ptr
的一个重要的事情是只用以下语法构造它们:
shared_ptr<Type>(new Type(...));
这样, Type
的“真正”指针对你的作用域是匿名的, 只有共享指针才能保持。 因此,你不可能不小心使用这个“真正的”指针。 换句话说,永远不要这样做:
Type* t_ptr = new Type(...); shared_ptr<Type> t_sptr ptrT(t_ptr); //t_ptr is still hanging around! Don't use it!
虽然这会起作用,但是现在您的函数中有一个Type*
指针( t_ptr
),它位于共享指针之外。 在任何地方使用t_ptr
很危险的,因为你永远不知道什么时候持有它的共享指针可能会破坏它,而且会发生段错误。
其他类返回给你的指针也是一样的。 如果你没有写的类给你一个指针,把它放在shared_ptr
通常是不安全的。 除非您确定课程不再使用该对象。 因为如果你把它放在一个shared_ptr
,并且超出了范围,当这个类可能还需要的时候,这个对象将被释放。
学习使用智能指针是我认为成为一个有能力的C ++程序员最重要的步骤之一。 正如你所知道的,每当你新增一个对象的时候,你想删除它。
出现的一个问题是,在例外情况下,确保一个对象总是只在所有可能的执行path中释放一次是非常困难的。
这是RAII的原因: http : //en.wikipedia.org/wiki/RAII
创build一个辅助类,目的是确保一个对象在所有执行path中总是被删除一次。
像这样的类的例子是:std :: auto_ptr
但有时你喜欢与其他人分享对象。 只有在没有人使用它时才应该删除它。
为了帮助引用计数策略已经开发出来,但是您仍然需要手动记住addref并释放ref。 本质上这是新/删除相同的问题。
这就是为什么boost已经开发boost :: shared_ptr,它是引用计数智能指针,所以你可以共享对象,而不是无意中泄漏内存。
随着C + + tr1的join,现在它被添加到c ++标准中,但是它的名字是std :: tr1 :: shared_ptr <>。
如果可能,我build议使用标准的共享指针。 ptr_list,ptr_dequeue等是指针types的IIRC专用容器。 我现在忽略他们。
所以我们可以从你的例子开始:
std::vector<gate*> G; G.push_back(new ANDgate); G.push_back(new ORgate); for(unsigned i=0;i<G.size();++i) { G[i]->Run(); }
这里的问题是现在每当G超出范围,我们泄漏添加到G的2个对象。让我们重写它使用std :: tr1 :: shared_ptr
// Remember to include <memory> for shared_ptr // First do an alias for std::tr1::shared_ptr<gate> so we don't have to // type that in every place. Call it gate_ptr. This is what typedef does. typedef std::tr1::shared_ptr<gate> gate_ptr; // gate_ptr is now our "smart" pointer. So let's make a vector out of it. std::vector<gate_ptr> G; // these smart_ptrs can't be implicitly created from gate* we have to be explicit about it // gate_ptr (new ANDgate), it's a good thing: G.push_back(gate_ptr (new ANDgate)); G.push_back(gate_ptr (new ORgate)); for(unsigned i=0;i<G.size();++i) { G[i]->Run(); }
当G超出范围时,内存自动回收。
作为一个在我的团队中困扰新人的练习,是要求他们写自己的智能指针课。 然后,你完成后立即丢弃类,不再使用它。 希望你获得关于智能指针如何工作的关键知识。 真的没有魔法
boost文档提供了一个非常好的开始示例: shared_ptr示例 (实际上是关于智能指针的向量)或shared_ptr doc Johannes Schaub的以下答案很好地解释了boost智能指针: 智能指针解释
背后的想法(尽可能less的话)ptr_vector是它为你处理存储指针背后的内存释放:假设你有一个指针向量,如你的例子。 当退出应用程序或离开定义向量的范围时,您必须自行清理(您已经dynamic分配了ANDgate和ORgate),但只是清除向量不会执行此操作,因为向量正在存储指针而不是实际的对象(它不会破坏,而是包含它)。
// if you just do G.clear() // will clear the vector but you'll be left with 2 memory leaks ... // to properly clean the vector and the objects behind it for (std::vector<gate*>::iterator it = G.begin(); it != G.end(); it++) { delete (*it); }
boost :: ptr_vector <>将为你处理上面的内容 – 这意味着它将释放它存储的指针后面的内存。
通过提升你可以做到这一点>
std::vector<boost::any> vecobj; boost::shared_ptr<string> sharedString1(new string("abcdxyz!")); boost::shared_ptr<int> sharedint1(new int(10)); vecobj.push_back(sharedString1); vecobj.push_back(sharedint1);
>用于在向量容器中插入不同的对象types。 而访问你必须使用any_cast,它像dynamic_cast一样工作,希望它可以满足你的需要。
#include <memory> #include <iostream> class SharedMemory { public: SharedMemory(int* x):_capture(x){} int* get() { return (_capture.get()); } protected: std::shared_ptr<int> _capture; }; int main(int , char**){ SharedMemory *_obj1= new SharedMemory(new int(10)); SharedMemory *_obj2 = new SharedMemory(*_obj1); std::cout << " _obj1: " << *_obj1->get() << " _obj2: " << *_obj2->get() << std::endl; delete _obj2; std::cout << " _obj1: " << *_obj1->get() << std::endl; delete _obj1; std::cout << " done " << std::endl; }
这是shared_ptr的一个例子。 _obj2被删除,但指针仍然有效。 输出是,./test _obj1:10 _obj2:10 _obj2:10完成