std::shared_ptr<A> p1(new A());
std::shared_ptr<A> p2(p1); // p2 역시 생성된 객체 A 를 가리킨다.
shared_ptr
내부에 참조 개수를 저장한다면 생기는 문제
아래 코드의 경우 p1
에 저장된 참조 개수를 건드릴 수 없음
std::shared_ptr<A> p1(new A());
std::shared_ptr<A> p2(p1);
std::shared_ptr<A> p3(p2);
위 문제를 해결하는 방법
shared_ptr
가 제어블록을 동적으로 할당한 후, shared_ptr
들이 이 제어 블록에 필요한 정보를 공유하는 방식으로 구현됨std::shared_ptr<A> p1(new A());
shared_ptr
의 제어 블록 역시 동적으로 할당해야 하기 때문std::shared_ptr<A> p1 = std::make_shared<A>();
make_shared
함수는 A의 생성자의 인자들을 받아서 이를 통해 객체 A와 shared_ptr
의 제어 블록까지 한 번에 동적할당 한 후에 만들어진 shared_ptr
을 리턴shared_ptr
은 인자로 주소값이 전달되면, 마치 자기가 해당 객체를 첫번째로 소유하는 shared_ptr
인 것 마냥 행동함
A* a = new A();
std::shared_ptr<A> pa1(a);
std::shared_ptr<A> pa2(a);
객체 내부에서 자기 자신을 가리키는 shared_ptr
을 만들 때는 예외
#include <iostream>
#include <memory>
class A {
int *data;
public:
A() {
data = new int[100];
std::cout << "자원을 획득함!" << std::endl;
}
~A() {
std::cout << "소멸자 호출!" << std::endl;
delete[] data;
}
std::shared_ptr<A> get_shared_ptr() { return std::shared_ptr<A>(this); }
};
int main() {
std::shared_ptr<A> pa1 = std::make_shared<A>();
std::shared_ptr<A> pa2 = pa1->get_shared_ptr();
std::cout << pa1.use_count() << std::endl;
std::cout << pa2.use_count() << std::endl;
}
shared_ptr
가 있다는 사실을 모른채 새로운 제어 블록을 생성하기 때문enable_shared_from_this
를 통해 해결가능shared_ptr
이 반드시 먼저 정의되어 있어야만 가능std::shared_ptr<A> get_shared_ptr() { return shared_from_this(); }
shared_ptr
이 서로 참조하게 되면 참조개수가 절대로 0이 될 수 없음(순환 참조
)weak_ptr
을 통해 해결 가능shared_ptr
로 만든다면, 부모노드와 자식노드가 서로를 가리키기 때문에 순환참조가 발생weak_ptr
은 일반 포인터와 shared_ptr
사이에 위치한 스마트 포인터로, 스마트 포인터 처럼 객체를 안전하게 참조할 수 있게 해주지만, shared_ptr
와는 다르게 참조 개수를 늘리진 않음weak_ptr
가 가리키고 있더라도 다른 shared_ptr
들이 가리키고 있지 않다면 메모리에서 소멸됨weak_ptr
자체로는 원래 객체를 참조할 수 없고, 반드시 shared_ptr
로 변환해 사용해야 함shared_ptr
로 변환shared_ptr
로 변환#include <iostream>
#include <memory>
#include <string>
#include <vector>
class A {
std::string s;
std::weak_ptr<A> other;
public:
A(const std::string& s) : s(s) { std::cout << "자원을 획득함!" << std::endl; }
~A() { std::cout << "소멸자 호출!" << std::endl; }
void set_other(std::weak_ptr<A> o) { other = o; }
void access_other() {
std::shared_ptr<A> o = other.lock();
if (o) {
std::cout << "접근 : " << o->name() << std::endl;
} else {
std::cout << "이미 소멸됨 ㅠ" << std::endl;
}
}
std::string name() { return s; }
};
int main() {
std::vector<std::shared_ptr<A>> vec;
vec.push_back(std::make_shared<A>("자원 1"));
vec.push_back(std::make_shared<A>("자원 2"));
vec[0]->set_other(vec[1]);
vec[1]->set_other(vec[0]);
// pa 와 pb 의 ref count 는 그대로다.
std::cout << "vec[0] ref count : " << vec[0].use_count() << std::endl;
std::cout << "vec[1] ref count : " << vec[1].use_count() << std::endl;
// weak_ptr 로 해당 객체 접근하기
vec[0]->access_other();
// 벡터 마지막 원소 제거 (vec[1] 소멸)
vec.pop_back();
vec[0]->access_other(); // 접근 실패!
}
자원을 획득함!
자원을 획득함!
vec[0] ref count : 1
vec[1] ref count : 1
접근 : 자원 2
소멸자 호출!
이미 소멸됨 ㅠ
소멸자 호출!