使用 share_ptr 的示例?

嗨,我今天问了一个关于 如何在同一向量数组中插入不同类型的对象的问题,我在这个问题中的代码是

 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
}

我想用矢量,所以有人写道,我应该这样做:

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();
}

但后来他和许多其他人建议我最好使用 Boost 指针容器
shared_ptr。我已经花了3个小时阅读这个主题,但文档对我来说似乎相当高级。* * * 有人能给我一个 shared_ptr使用的小代码示例,以及为什么他们建议使用 shared_ptr。也有其他类型,如 ptr_vectorptr_listptr_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 );
...........
}

我不懂这句话的语法!

175995 次浏览

在我看来,学习使用智能指针是成为一名称职的 C + + 程序员最重要的步骤之一。正如您所知道的,每当您在某个时刻新建一个对象时,您都希望删除它。

出现的一个问题是,对于异常,很难确保在所有可能的执行路径中总是释放一次对象。

这就是 RAII: http://en.wikipedia.org/wiki/RAII的原因

创建一个 helper 类,目的是确保对象总是在所有执行路径中删除一次。

这样的类的示例是: std: : auto _ ptr

但是有时候你喜欢和其他人共享对象。只有当没有人再使用它的时候才应该删除它。

为了帮助解决这个问题,已经开发了引用计数策略,但是仍然需要手动记住地址和发布引用。本质上,这与 new/delete 是相同的问题。

这就是为什么升级开发了升级: : share _ ptr,它是引用计数智能指针,这样你就可以共享对象,而不会无意中泄漏内存。

随着 C + + tr1的添加,现在它也被添加到了 c + + 标准中,但是它的名字是 std: : tr1: : share _ ptr < > 。

如果可能的话,我建议使用标准的共享指针。Ptr _ list、 ptr _ dequeue 等都是 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: : share _ 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 超出作用域时,内存将被自动回收。

作为一个困扰我的团队中的新人的练习,我要求他们编写他们自己的智能指针类。然后在你完成后立即丢弃类,并且永远不再使用它。希望您获得了关于智能指针如何在引擎盖下工作的关键知识。根本没有什么魔法。

升级文档提供了一个很好的开始示例: Share _ ptr example (它实际上是关于智能指针的向量)或 Share _ ptr doc 共享 _ ptr 文档 Johannes Schaub 的以下回答很好地解释了智能指针的提升: 聪明的指示解释

Ptr _ Vector 背后的思想(尽可能简单)是它为您处理存储指针后面的内存释放: 假设您有一个指针向量,就像您的示例一样。当退出应用程序或离开定义向量的作用域时,你必须自己清理(你已经动态地分配了 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);
}

Ptr _ Vector < > 将为您处理以上内容——这意味着它将释放其存储的指针背后的内存。

使用 shared_ptrvector可以消除内存泄漏的可能性,因为您忘记遍历向量并对每个元素调用 delete。让我们逐行浏览这个示例的一个稍微修改过的版本。

typedef boost::shared_ptr<gate> gate_ptr;

为共享指针类型创建别名。这样就避免了 C + + 语言中键入 std::vector<boost::shared_ptr<gate> >和忘记关闭的 大于征兆之间的空格导致的丑陋。

    std::vector<gate_ptr> vec;

创建 boost::shared_ptr<gate>对象的空向量。

    gate_ptr ptr(new ANDgate);

分配一个新的 ANDgate实例并将其存储到 shared_ptr中。单独执行此操作的原因是为了防止操作抛出。在这个例子中这是不可能的。提升 shared_ptr“最佳实践”解释了为什么分配到独立对象而不是临时对象是 最佳实践

    vec.push_back(ptr);

这将在向量中创建一个新的共享指针,并将 ptr复制到其中。shared_ptr内核中的引用计数确保了 ptr内部分配的对象被安全地转移到向量中。

没有解释的是,shared_ptr<gate>的析构函数确保删除分配的内存。这就是避免内存泄漏的地方。std::vector<T>的析构函数确保对存储在向量中的每个元素调用 T的析构函数。但是,指针(例如,gate*)的析构函数 不会删除已分配的内存。这就是你试图通过使用 shared_ptrptr_vector来避免的。

我要补充的是,关于 shared_ptr的一个重要的事情是,只有 永远不会使用以下语法构造它们:

shared_ptr<Type>(new Type(...));

这样,指向 Type的“ real”指针对作用域是匿名的,由共享指针保存 只有。因此,您将不可能意外地使用这个“真正的”指针。换句话说,永远不要这样做:

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都是危险的,因为您永远不知道持有它的共享指针何时可能会破坏它,并且您将使用 sefault。

其他类返回给您的指针也是如此。如果一个你没有写的类给你一个指针,把它放在 shared_ptr里通常是不安全的。除非您是 当然,否则类不再使用该对象。因为如果您将其放入 shared_ptr中,而它超出了作用域,那么当类可能仍然需要该对象时,该对象将被释放。

通过 Boost 你可以做到 >

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);

> 用于在向量容器中插入不同的对象类型。虽然访问时必须使用 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;
}

这是一个执行中的 share _ ptr 示例。 _ objec2已被删除,但指针仍然有效。 输出是, 。/测试 _ objec1:10 _ objec2:10 _ objec2:10 搞定

将不同的对象添加到同一个容器中的最佳方法是使用 make _ share、 Vector 和 range 基于循环,这样您将得到一个漂亮、干净和“可读”的代码!

typedef std::shared_ptr<gate> Ptr
vector<Ptr> myConatiner;
auto andGate = std::make_shared<ANDgate>();
myConatiner.push_back(andGate );
auto orGate= std::make_shared<ORgate>();
myConatiner.push_back(orGate);


for (auto& element : myConatiner)
element->run();