shared_ptr의 기본 사용법
shared_ptr은 참조 카운팅을 사용하여 가리키는 객체를 관리합니다. 동일한 객체를 가리키는 새로운 shared_ptr이 있으면(shared_ptr 복사 등) 참조 횟수가 1씩 증가합니다. shared_ptr이 범위를 벗어나면 참조 횟수가 1씩 감소합니다. 참조 횟수가 0이 되면 관리되는 메모리가 해제됩니다.
이것의 장점은 프로그래머가 수동으로 메모리를 해제해야 하는 부담을 덜어준다는 것입니다. 과거에는 프로그램에서 예외를 처리하기 위해 포인터를 클래스로 수동으로 캡슐화하고 소멸자를 사용하여 동적으로 할당된 메모리를 해제해야 하는 경우가 많았습니다. 이제 이 프로세스를 shared_ptr에 맡길 수 있습니다.
일반적으로 우리는 make_shared를 사용하여 shared_ptr을 얻습니다.
cout<<"test shared_ptr base usage:"<<endl; shared_ptr<string> p1 = make_shared<string>(""); if(p1 && p1->empty()) *p1 = "hello"; auto p2 = make_shared<string>("world"); cout<<*p1<<' '<<*p2<<endl; cout<<"test shared_ptr use_count:"<<endl; cout<<"p1 cnt:"<<p1.use_count()<<"\tp2 cnt:"<<p2.use_count()<<endl; auto p3 = p2; cout<<"p1 cnt:"<<p1.use_count()<<"\tp2 cnt:"<<p2.use_count()<<"\tp3 cnt:"<<p3.use_count()<<endl; p2 = p1; cout<<"p1 cnt:"<<p1.use_count()<<"\tp2 cnt:"<<p2.use_count()<<"\tp3 cnt:"<<p3.use_count()<<endl;
shared_ptr 및 new
shared_ptr은 새 표현식에서 반환된 포인터를 사용하여 초기화할 수 있습니다.
cout<<"test shared_ptr and new:"<<endl; shared_ptr<int> p4(new int(1024)); //shared_ptr<int> p5 = new int(1024); // wrong, no implicit constructor cout<<*p4<<endl;
그러나 새 표현식에서 반환된 포인터는 shared_ptr에 할당될 수 없습니다.
또한 new와 shared_ptr을 혼합하지 않도록 특별한 주의를 기울여야 합니다!
void process(shared_ptr<int> ptr) { cout<<"in process use_count:"<<ptr.use_count()<<endl; } cout<<"don't mix shared_ptr and normal pointer:"<<endl; shared_ptr<int> p5(new int(1024)); process(p5); int v5 = *p5; cout<<"v5: "<<v5<<endl; int *p6 = new int(1024); process(shared_ptr<int>(p6)); int v6 = *p6; cout<<"v6: "<<v6<<endl;
위 프로그램 조각은 다음을 출력합니다.
in process use_count:2
v5: 1024
in process use_count:1
v6: 0
프로세스 p6을 두 번째로 사용할 때 shared_ptr의 참조 횟수가 는 1이고, 프로세스 범위에 도달하면 해당 메모리가 해제되고 p6은 정지 포인터가 됩니다.
따라서 새 표현식에서 반환된 포인터가 shared_ptr에 의해 관리되면 일반 포인터를 통해 이 메모리에 액세스하지 마세요!
shared_ptr.reset
shared_ptr은 재설정 메소드를 통해 다른 객체를 가리키도록 재설정될 수 있으며 이때 원래 객체의 참조 횟수는 1만큼 감소합니다.
cout<<"test shared_ptr reset:"<<endl; cout<<"p1 cnt:"<<p1.use_count()<<"\tp2 cnt:"<<p2.use_count()<<"\tp3 nt:"<<p3.use_count()<<endl; p1.reset(new string("cpp11")); cout<<"p1 cnt:"<<p1.use_count()<<"\tp2 cnt:"<<p2.use_count()<<"\tp3 cnt:"<<p3.use_count()<<endl; shared_ptr deleter
shared_ptr이 객체를 해제할 때 호출되도록 삭제 함수를 사용자 정의할 수 있습니다.
void print_at_delete(int *p) { cout<<"deleting..."<<p<<'\t'<<*p<<endl; delete p; } cout<<"test shared_ptr deleter:"<<endl; int *p7 = new int(1024); shared_ptr<int> p8(p7, print_at_delete); p8 = make_shared<int>(1025);
unique_ptr 기본 사용법
unique_ptr은 이름에서 알 수 있듯이 가리키는 개체에만 적용됩니다. 따라서 Unique_ptr은 복사, 할당 등이 불가능하지만, release 기능을 통해 Unique_ptr 간에 제어권이 전달될 수 있습니다.
cout<<"test unique_ptr base usage:"<<endl; unique_ptr<int> up1(new int(1024)); cout<<"up1: "<<*up1<<endl; unique_ptr<int> up2(up1.release()); cout<<"up2: "<<*up2<<endl; //unique_ptr<int> up3(up1); // wrong, unique_ptr can not copy //up2 = up1; // wrong, unique_ptr can not copy unique_ptr<int> up4(new int(1025)); up4.reset(up2.release()); cout<<"up4: "<<*up4<<endl;
unique_ptr을 매개변수와 반환값으로
위의 복사 제한에는 두 가지 특수한 경우가 있습니다. 즉, Unique_ptr을 사용할 수 있습니다. 함수의 반환 값으로 값과 매개변수가 사용됩니다. 이때 암시적 복사본이 있지만 실행 불가능하지는 않습니다.
unique_ptr<int> clone(int p) { return unique_ptr<int>(new int(p)); } void process_unique_ptr(unique_ptr<int> up) { cout<<"process unique ptr: "<<*up<<endl; } cout<<"test unique_ptr parameter and return value:"<<endl; auto up5 = clone(1024); cout<<"up5: "<<*up5<<endl; process_unique_ptr(move(up5)); //cout<<"up5 after process: "<<*up5<<endl; // would cause segmentfault
여기서 std::move 함수에 대해서는 나중에 자세히 설명합니다^_^
unique_ptr deleter
Unique_ptr deleter를 설정할 수도 있습니다. shared_ptr과 달리 템플릿 매개변수에 deleter 유형을 지정해야 합니다. 다행스럽게도 우리는 강력한 도구인 decltype을 가지고 있습니다. 그렇지 않으면 작성하기가 어려울 것입니다.
cout<<"test unique_ptr deleter:"<<endl; int *p9 = new int(1024); unique_ptr<int, decltype(print_at_delete) *> up6(p9, print_at_delete); unique_ptr<int> up7(new int(1025)); up6.reset(up7.release());
weak_ptr
weak_ptr은 일반적으로 shared_ptr과 함께 사용됩니다. shared_ptr이 가리키는 개체를 가리킬 수 있지만 개체의 참조 횟수는 증가하지 않습니다. 이런 식으로 Weak_ptr이 가리키는 객체가 실제로 해제되었을 가능성이 있습니다. 따라서 Weak_ptr에는 개체를 가리키는 shared_ptr을 검색하려고 시도하는 잠금 기능이 있습니다.
cout<<"test weak_ptr basic usage:"<<endl; auto p10 = make_shared<int>(1024); weak_ptr<int> wp1(p10); cout<<"p10 use_count: "<<p10.use_count()<<endl; //p10.reset(new int(1025)); // this will cause wp1.lock() return a false obj shared_ptr<int> p11 = wp1.lock(); if(p11) cout<<"wp1: "<<*p11<<" use count: "<<p11.use_count()<<endl;
요약
shared_ptr은 참조 카운팅을 사용하여 가리키는 개체를 관리합니다.
Shared_ptr은 새 표현식에서 반환된 포인터를 사용하여 초기화될 수 있지만 새 표현식에서 반환된 포인터는 shared_ptr에 할당될 수 없습니다.
새 표현식에서 반환된 포인터가 shared_ptr에 의해 관리되면 일반 포인터를 통해 이 메모리에 액세스하지 마세요.
shared_ptr은 Reset 메소드를 통해 다른 객체를 가리키도록 재설정할 수 있습니다. 이때 원본 객체의 참조 횟수는 1씩 감소합니다.
shared_ptr이 객체를 해제할 때 호출되도록 삭제 함수를 사용자 정의할 수 있습니다.
unique_ptr은 가리키는 객체에만 배타적입니다.
Unique_ptr은 복사, 할당 등이 불가능하지만, release 기능을 통해 Unique_ptr 간에 제어권이 이전될 수 있습니다.
unique_ptr은 함수의 반환값과 매개변수로 사용될 수 있습니다.
unique_ptr은 삭제자를 설정할 수도 있으며 삭제자의 유형은 템플릿 매개변수에 지정되어야 합니다.
Weak_ptr은 일반적으로 shared_ptr과 함께 사용됩니다. shared_ptr이 가리키는 개체를 가리킬 수 있지만 개체의 참조 횟수는 증가하지 않습니다.
Weak_ptr에는 객체를 가리키는 shared_ptr을 검색하려고 시도하는 잠금 기능이 있습니다.
위 내용은 이 글의 전체 내용입니다. 모든 분들의 학습에 도움이 되기를 바랍니다.
C++11의 새로운 기능인 스마트 포인터(shared_ptr/unique_ptr/weak_ptr)와 관련된 더 많은 기사를 보려면 PHP 중국어 웹사이트를 주목하세요!