나는 가로 질러 enable_shared_from_this
Boost.Asio 예제를 읽는 동안 나는 여전히 올바르게 사용하는 방법에 대한 분실하고있는 문서를 읽고. 누군가이 수업을 사용할 때의 설명과 설명을 해 줄 수 있습니까?
답변
당신이 가진 모든 경우에 유효한 shared_ptr
인스턴스 를 얻을 수 있습니다 . 그게 없으면, 당신은을 얻는 방법이없는 것 에 이미 구성원으로 일했다하지 않는 한을. enable_shared_from_this에 대한 부스트 문서 의이 예제는 다음과 같습니다.this
this
shared_ptr
this
class Y: public enable_shared_from_this<Y>
{
public:
shared_ptr<Y> f()
{
return shared_from_this();
}
}
int main()
{
shared_ptr<Y> p(new Y);
shared_ptr<Y> q = p->f();
assert(p == q);
assert(!(p < q || q < p)); // p and q must share ownership
}
멤버 인스턴스가 f()
없더라도이 메소드 는 valid를 리턴 shared_ptr
합니다. 간단히 이렇게 할 수는 없습니다.
class Y: public enable_shared_from_this<Y>
{
public:
shared_ptr<Y> f()
{
return shared_ptr<Y>(this);
}
}
이것에 의해 반환 된 공유 포인터는 “적절한”참조와는 다른 참조 카운트를 가지게되며, 그중 하나는 객체가 삭제 될 때 매달려있는 참조를 잃어 버릴 수 있습니다.
enable_shared_from_this
C ++ 11 표준의 일부가되었습니다. 부스트뿐만 아니라 거기에서도 얻을 수 있습니다.
답변
약한 포인터에 대한 Dr Dobbs 기사 에서이 예제를 이해하기 쉽다고 생각합니다 (출처 : http://drdobbs.com/cpp/184402026 ).
… 이와 같은 코드는 올바르게 작동하지 않습니다.
int *ip = new int;
shared_ptr<int> sp1(ip);
shared_ptr<int> sp2(ip);
둘 중 어느 것도 shared_ptr
개체 다른 개체에 대해 알지 못하므로 개체가 모두 파괴되면 리소스를 해제하려고합니다. 일반적으로 문제가 발생합니다.
마찬가지로 멤버 함수에 호출되는 shared_ptr
객체를 소유 한 객체가 필요한 경우 즉시 객체를 만들 수 없습니다.
struct S
{
shared_ptr<S> dangerous()
{
return shared_ptr<S>(this); // don't do this!
}
};
int main()
{
shared_ptr<S> sp1(new S);
shared_ptr<S> sp2 = sp1->dangerous();
return 0;
}
이 코드는 이전 예제와 같은 문제가 있지만 더 미묘한 형식입니다. 그것이 구축 될 때, shared_pt
r 객체 sp1
는 새로 할당 된 리소스를 소유합니다. 멤버 함수 내부의 코드 S::dangerous
는 해당 shared_ptr
객체 에 대해 알지 못 하므로 shared_ptr
반환 되는 객체는와 다릅니다 sp1
. 새 shared_ptr
객체를 복사 sp2
해도 도움이되지 않습니다. 때 sp2
범위를 벗어나, 그것은 리소스를 분리 한 경우 것이다 sp1
범위를 벗어나, 다시 리소스를 해제합니다.
이 문제를 피하는 방법은 클래스 템플릿을 사용하는 것 enable_shared_from_this
입니다. 템플리트는 하나의 템플리트 유형 인수를 사용하는데, 이는 관리 자원을 정의하는 클래스의 이름입니다. 해당 클래스는 템플릿에서 공개적으로 파생되어야합니다. 이처럼 :
struct S : enable_shared_from_this<S>
{
shared_ptr<S> not_dangerous()
{
return shared_from_this();
}
};
int main()
{
shared_ptr<S> sp1(new S);
shared_ptr<S> sp2 = sp1->not_dangerous();
return 0;
}
이 작업을 수행 할 때 호출 shared_from_this
하는 shared_ptr
객체 는 객체 가 소유해야 합니다. 작동하지 않습니다.
int main()
{
S *p = new S;
shared_ptr<S> sp2 = p->not_dangerous(); // don't do this
}
답변
여기에 볼트와 너트 관점에서 내 설명이 있습니다 (최고의 답변은 나와 ‘클릭’하지 않았습니다). * 이것은 Visual Studio 2012와 함께 제공되는 shared_ptr 및 enable_shared_from_this의 소스를 조사한 결과입니다. 아마도 다른 컴파일러는 enable_shared_from_this를 다르게 구현합니다 … *
enable_shared_from_this<T>
의 weak_ptr<T>
인스턴스에 T
대한 ‘ 하나의 참 참조 카운트 ‘를 보유 하는 프라이빗 인스턴스를 추가합니다 T
.
따라서 shared_ptr<T>
새로운 T *에 처음으로를 생성하면 해당 T *의 내부 weak_ptr이 1의 참조 횟수로 초기화됩니다. 새로운 shared_ptr
기본적으로이로 돌아 weak_ptr
갑니다.
T
그리고, 그 방법으로 호출 할 수 shared_from_this
의 인스턴스를 획득하기 위해 shared_ptr<T>
그 같은 내부에 저장된 레퍼런스 카운트에 뒤를 . 이렇게하면 항상 서로에 대해 알지 못하는 T*
여러 shared_ptr
인스턴스가 아닌 참조 횟수가 저장 되는 한 곳이 있으며 , 각 shared_ptr
참조 횟수는 참조 횟수를 계산 T
하고 참조 할 때 삭제하는 담당자 라고 생각합니다. -카운트가 0에 도달합니다.
답변
boost :: intrusive_ptr을 사용하면이 문제가 발생하지 않습니다. 이것은 종종이 문제를 해결하는 더 편리한 방법입니다.
답변
c ++ 11 이상에서 정확히 동일 합니다. 원시 포인터를 제공 this
하므로 공유 포인터 로 반환 this
할 수 있습니다.
다시 말해, 이처럼 코드를 바꿀 수 있습니다
class Node {
public:
Node* getParent const() {
if (m_parent) {
return m_parent;
} else {
return this;
}
}
private:
Node * m_parent = nullptr;
};
이것으로 :
class Node : std::enable_shared_from_this<Node> {
public:
std::shared_ptr<Node> getParent const() {
std::shared_ptr<Node> parent = m_parent.lock();
if (parent) {
return parent;
} else {
return shared_from_this();
}
}
private:
std::weak_ptr<Node> m_parent;
};
답변
다른 방법은에 weak_ptr<Y> m_stub
멤버 를 추가하는 것 class Y
입니다. 그런 다음 다음을 작성하십시오.
shared_ptr<Y> Y::f()
{
return m_stub.lock();
}
파생하는 수업을 변경할 수없는 경우에 유용합니다 (예 : 다른 사람의 도서관 확장). 멤버를 초기화하는 것을 잊지 마십시오 (예 : by m_stub = shared_ptr<Y>(this)
)는 생성자 중에도 유효합니다.
상속 계층 구조에 이와 같은 스텁이 더 있으면 오브젝트가 손상되지 않습니다.
편집 : 사용자 nobar가 올바르게 지적한 것처럼 코드는 할당이 완료되고 임시 변수가 파괴되면 Y 객체를 파괴합니다. 따라서 내 대답이 잘못되었습니다.