C++ 使用 shared_ptr 的示例?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3476938/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 12:55:12  来源:igfitidea点击:

Example to use shared_ptr?

c++boostvectorshared-ptrsmart-pointers

提问by Ahmed

Hi I asked a question today about How to insert different types of objects in the same vector array and my code in that question was

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

 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
 } 

and I wanted to use vectors so someone wrote that I should do that :

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

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

but then he and many others suggested that I would better use Boost pointer containers
or shared_ptr. I have spent the last 3 hours reading about this topic, but the documentation seems pretty advanced to me . ****Can anyone give me a small code example of shared_ptrusage and why they suggested using shared_ptr. Also are there other types like ptr_vector, ptr_listand ptr_deque** **

但随后他和许多其他人建议我最好使用Boost 指针容器
shared_ptr. 在过去的 3 个小时里,我一直在阅读有关此主题的信息,但文档对我来说似乎相当先进。****谁能给我一个shared_ptr使用的小代码示例以及他们为什么建议使用shared_ptr. 还有其他类型,如ptr_vector,ptr_listptr_deque** **

Edit1: I have read a code example too that included:

Edit1:我也阅读了一个代码示例,其中包括:

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

And I don't understand the syntax!

而且我不懂语法!

回答by D.Shawley

Using a vectorof shared_ptrremoves the possibility of leaking memory because you forgot to walk the vector and call deleteon each element. Let's walk through a slightly modified version of the example line-by-line.

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

typedef boost::shared_ptr<gate> gate_ptr;

Create an alias for the shared pointer type. This avoids the ugliness in the C++ language that results from typing std::vector<boost::shared_ptr<gate> >and forgetting the space between the closing greater-than signs.

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

    std::vector<gate_ptr> vec;

Creates an empty vector of boost::shared_ptr<gate>objects.

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

    gate_ptr ptr(new ANDgate);

Allocate a new ANDgateinstance and store it into a shared_ptr. The reason for doing this separately is to prevent a problem that can occur if an operation throws. This isn't possible in this example. The Boost shared_ptr"Best Practices"explain why it is a best practiceto allocate into a free-standing object instead of a temporary.

分配一个新ANDgate实例并将其存储到shared_ptr. 单独执行此操作的原因是为了防止在操作抛出时可能出现的问题。在这个例子中这是不可能的。该升压shared_ptr“最佳实践”解释了为什么这是一个最好的做法来分配到一个独立的对象,而不是暂时的。

    vec.push_back(ptr);

This creates a new shared pointer in the vector and copies ptrinto it. The reference counting in the guts of shared_ptrensures that the allocated object inside of ptris safely transferred into the vector.

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

What is not explained is that the destructor for shared_ptr<gate>ensures that the allocated memory is deleted. This is where the memory leak is avoided. The destructor for std::vector<T>ensures that the destructor for Tis called for every element stored in the vector. However, the destructor for a pointer (e.g., gate*) does not delete the memory that you had allocated. That is what you are trying to avoid by using shared_ptror ptr_vector.

没有说明的是,析构函数 forshared_ptr<gate>确保分配的内存被删除。这是避免内存泄漏的地方。析构函数 forstd::vector<T>确保T为存储在向量中的每个元素调用析构函数 for 。但是,指针(例如gate*)的析构函数不会删除您分配的内存。这就是您试图通过使用shared_ptror来避免的ptr_vector

回答by Ken Simon

I will add that one of the important things about shared_ptr's is to only everconstruct them with the following syntax:

我将增加约重要的事情是一个shared_ptr的是只有不断构建他们的语法如下:

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

This way, the "real" pointer to Typeis anonymous to your scope, and held onlyby the shared pointer. Thus it will be impossible for you to accidentally use this "real" pointer. In other words, never do this:

这样,指向的“真实”指针对于Type您的作用域是匿名的,并且由共享指针持有。因此,您不可能不小心使用这个“真实”的指针。换句话说,永远不要这样做:

Type* t_ptr = new Type(...);
shared_ptr<Type> t_sptr ptrT(t_ptr);
//t_ptr is still hanging around!  Don't use it!

Although this will work, you now have a Type*pointer (t_ptr) in your function which lives outside the shared pointer. It's dangerous to use t_ptranywhere, because you never know when the shared pointer which holds it may destruct it, and you'll segfault.

尽管这会起作用,但您现在的函数中有一个Type*指针 ( t_ptr),它位于共享指针之外。在t_ptr任何地方使用都是危险的,因为您永远不知道持有它的共享指针何时可能破坏它,并且您会出现段错误。

Same goes for pointers returned to you by other classes. If a class you didn't write hands you a pointer, it's generally not safe to just put it in a shared_ptr. Not unless you're surethat the class is no longer using that object. Because if you do put it in a shared_ptr, and it falls out of scope, the object will get freed when the class may still need it.

其他类返回给您的指针也是如此。如果一个不是你写的类给你一个指针,把它放在一个shared_ptr. 除非您确定该类不再使用该对象,否则不会。因为如果你确实把它放在 a 中shared_ptr,并且它超出了范围,那么当类可能仍然需要它时,该对象将被释放。

回答by Just another metaprogrammer

Learning to use smart pointers is in my opinion one of the most important steps to become a competent C++ programmer. As you know whenever you new an object at some point you want to delete it.

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

One issue that arise is that with exceptions it can be very hard to make sure a object is always released just once in all possible execution paths.

出现的一个问题是,除例外情况外,很难确保在所有可能的执行路径中始终只释放一次对象。

This is the reason for RAII: http://en.wikipedia.org/wiki/RAII

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

Making a helper class with purpose of making sure that an object always deleted once in all execution paths.

制作一个帮助类,目的是确保一个对象在所有执行路径中总是删除一次。

Example of a class like this is: std::auto_ptr

像这样的类的例子是:std::auto_ptr

But sometimes you like to share objects with other. It should only be deleted when none uses it anymore.

但有时您喜欢与他人共享对象。只有当没有人再使用它时才应该删除它。

In order to help with that reference counting strategies have been developed but you still need to remember addref and release ref manually. In essence this is the same problem as new/delete.

为了帮助已经开发了引用计数策略,但您仍然需要手动记住 addref 和 release ref。本质上,这与新建/删除的问题相同。

That's why boost has developed boost::shared_ptr, it's reference counting smart pointer so you can share objects and not leak memory unintentionally.

这就是 boost 开发 boost::shared_ptr 的原因,它是引用计数智能指针,因此您可以共享对象而不会无意中泄漏内存。

With the addition of C++ tr1 this is now added to the c++ standard as well but its named std::tr1::shared_ptr<>.

随着 C++ tr1 的添加,它现在也被添加到 C++ 标准中,但它的命名为 std::tr1::shared_ptr<>。

I recommend using the standard shared pointer if possible. ptr_list, ptr_dequeue and so are IIRC specialized containers for pointer types. I ignore them for now.

如果可能,我建议使用标准共享指针。ptr_list、ptr_dequeue 等都是 IIRC 专门用于指针类型的容器。我暂时忽略它们。

So we can start from your example:

所以我们可以从你的例子开始:

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

The problem here is now that whenever G goes out scope we leak the 2 objects added to G. Let's rewrite it to use std::tr1::shared_ptr

现在的问题是,每当 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(); 
} 

When G goes out of scope the memory is automatically reclaimed.

当 G 超出范围时,内存会自动回收。

As an exercise which I plagued newcomers in my team with is asking them to write their own smart pointer class. Then after you are done discard the class immedietly and never use it again. Hopefully you acquired crucial knowledge on how a smart pointer works under the hood. There's no magic really.

作为一个让我的团队中的新人感到困扰的练习,我要求他们编写自己的智能指针类。然后在您完成后立即丢弃该课程并且不再使用它。希望您获得了有关智能指针如何在幕后工作的重要知识。真的没有魔法。

回答by celavek

The boost documentation provides a pretty good start example: shared_ptr example(it's actually about a vector of smart pointers) or shared_ptr docThe following answer by Johannes Schaub explains the boost smart pointers pretty well: smart pointers explained

boost 文档提供了一个很好的开始示例: shared_ptr 示例(它实际上是关于智能指针的向量)或 shared_ptr docJohannes Schaub 的以下回答很好地解释了 boost 智能指针: 智能指针解释

The idea behind(in as few words as possible) ptr_vector is that it handles the deallocation of memory behind the stored pointers for you: let's say you have a vector of pointers as in your example. When quitting the application or leaving the scope in which the vector is defined you'll have to clean up after yourself(you've dynamically allocated ANDgate and ORgate) but just clearing the vector won't do it because the vector is storing the pointers and not the actual objects(it won't destroy but what it contains).

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

boost::ptr_vector<> will handle the above for you - meaning it will deallocate the memory behind the pointers it stores.

boost::ptr_vector<> 将为您处理上述问题 - 这意味着它将释放它存储的指针后面的内存。

回答by user1808932

Through Boost you can do it >

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

> for inserting different object type in your vector container. while for accessing you have to use any_cast, which works like dynamic_cast, hopes it will work for your need.

> 用于在您的矢量容器中插入不同的对象类型。而访问你必须使用any_cast,它的工作原理类似于dynamic_cast,希望它能满足你的需要。

回答by Syed Raihan

#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;
}

This is an example of shared_ptr in action. _obj2 was deleted but pointer is still valid. output is, ./test _obj1: 10 _obj2: 10 _obj2: 10 done

这是 shared_ptr 的一个例子。_obj2 已删除,但指针仍然有效。输出是,./test _obj1: 10 _obj2: 10 _obj2: 10 done

回答by Hooman

The best way to add different objects into same container is to use make_shared, vector, and range based loop and you will have a nice, clean and "readable" code!

将不同对象添加到同一个容器中的最佳方法是使用基于 make_shared、向量和范围的循环,您将拥有一个漂亮、干净且“可读”的代码!

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