Development Tip

shared_ptr을 사용하는 예?

yourdevel 2020. 10. 4. 13:34
반응형

shared_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_ptrshared_ptr. ptr_vector, ptr_listptr_deque** ** 같은 다른 유형도 있습니다.

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

그리고 구문을 이해하지 못합니다!


vectorof를 사용 shared_ptr하면 벡터를 걷고 delete각 요소를 호출하는 것을 잊었 기 때문에 메모리 누수 가능성 제거 됩니다. 예제의 약간 수정 된 버전을 한 줄씩 살펴 보겠습니다.

typedef boost::shared_ptr<gate> gate_ptr;

공유 포인터 유형에 대한 별칭을 만듭니다. 이렇게하면 std::vector<boost::shared_ptr<gate> >닫는 보다 큼 기호 사이의 공백 을 입력 하고 잊어 버리는 C ++ 언어의 추악함을 방지 할 수 있습니다 .

    std::vector<gate_ptr> vec;

boost::shared_ptr<gate>객체로 구성된 빈 벡터를 만듭니다 .

    gate_ptr ptr(new ANDgate);

ANDgate인스턴스를 할당하고 shared_ptr. 이 작업을 별도로 수행하는 이유는 작업이 throw 될 때 발생할 수있는 문제를 방지하기위한 것입니다. 이 예에서는 불가능합니다. 부스트는 shared_ptr"모범 사례" 그것이 이유를 설명하는 가장 좋은 방법 대신 임시의 독립 개체로 할당 할 수는.

    vec.push_back(ptr);

이렇게하면 벡터에 새 공유 포인터가 만들어지고 여기에 복사 ptr됩니다. 의 내부에있는 참조 계수는 shared_ptr내부에 할당 된 객체 ptr가 안전하게 벡터로 전송되도록합니다.

설명되지 않은 것은 소멸자 shared_ptr<gate>가 할당 된 메모리가 삭제되었는지 확인한다는 것입니다. 이것은 메모리 누수가 방지되는 곳입니다. 에 대한 소멸자 는 벡터에 저장된 모든 요소에 대해 std::vector<T>소멸자 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 ++ 프로그래머가되기위한 가장 중요한 단계 중 하나라고 생각합니다. 아시다시피 객체를 새로 만들 때마다 삭제하고 싶습니다.

발생하는 한 가지 문제는 예외가있는 경우 가능한 모든 실행 경로에서 객체가 항상 한 번만 해제되도록하는 것이 매우 어려울 수 있다는 것입니다.

이것이 RAII의 이유입니다 : http://en.wikipedia.org/wiki/RAII

객체가 모든 실행 경로에서 항상 한 번 삭제되도록하는 목적으로 도우미 클래스를 만듭니다.

이와 같은 클래스의 예는 다음과 같습니다. std :: auto_ptr

그러나 때로는 다른 사람과 물건을 공유하고 싶어합니다. 더 이상 사용하지 않는 경우에만 삭제해야합니다.

참조 계산 전략이 개발되었지만 여전히 addref를 기억하고 ref를 수동으로 해제해야합니다. 본질적으로 이것은 new / delete와 동일한 문제입니다.

이것이 boost가 boost :: 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.

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

// 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.

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.


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

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

 // 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.


Through Boost you can do it >

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.


#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


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!

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

참고URL : https://stackoverflow.com/questions/3476938/example-to-use-shared-ptr

반응형