std :: shared_ptr of this


101

저는 현재 스마트 포인터 사용법을 배우려고합니다. 그러나 몇 가지 실험을 수행하는 동안 포화 솔루션을 찾을 수없는 다음 상황을 발견했습니다.

클래스 A의 오브젝트가 클래스 B (자식)의 오브젝트의 상위가되지만 둘 다 서로를 알아야한다고 가정하십시오.

class A;
class B;

class A
{
public:
    void addChild(std::shared_ptr<B> child)
    {
        children->push_back(child);

        // How to do pass the pointer correctly?
        // child->setParent(this);  // wrong
        //                  ^^^^
    }

private:        
    std::list<std::shared_ptr<B>> children;
};

class B
{
public:
    setParent(std::shared_ptr<A> parent)
    {
        this->parent = parent;
    };

private:
    std::shared_ptr<A> parent;
};

문제는 클래스 A의 객체가 어떻게 std::shared_ptr자신의 ( this)를 자식에게 전달할 수 있습니까?

Boost 공유 포인터 ( Getting a boost::shared_ptrforthis )에 대한 솔루션 이 있지만 std::스마트 포인터를 사용하여이를 처리하는 방법은 무엇입니까?


2
다른 도구와 마찬가지로 적절할 때 사용해야합니다. 당신이 무엇을하고 있는지에 대한 스마트 포인터를 사용하는 것은 없습니다
YePhIcK

부스트와 비슷합니다. 를 참조하십시오 여기 .
juanchopanza

1
이것은 추상화 수준의 문제입니다. "this"가 힙의 메모리를 가리키는지도 모릅니다.
Vaughn Cato

글쎄, 언어는 그렇지 않지만 당신 은 그렇습니다. 어디에 있는지 추적하는 한 괜찮을 것입니다.
Alex

답변:


168

std::enable_shared_from_this바로이 목적을 위해. 당신은 그것으로부터 상속하고 당신은 .shared_from_this()클래스 내부에서 호출 할 수 있습니다 . 또한 여기에서 리소스 누출로 이어질 수있는 순환 종속성을 생성하고 있습니다. 이 문제는 std::weak_ptr. 따라서 코드는 다음과 같이 보일 수 있습니다 (자녀가 부모의 존재에 의존하고 그 반대가 아니라고 가정).

class A;
class B;

class A
    : public std::enable_shared_from_this<A>
{
public:
    void addChild(std::shared_ptr<B> child)
    {
        children.push_back(child);

        // like this
        child->setParent(shared_from_this());  // ok
        //               ^^^^^^^^^^^^^^^^^^
    }

private:     
    // note weak_ptr   
    std::list<std::weak_ptr<B>> children;
    //             ^^^^^^^^
};

class B
{
public:
    void setParent(std::shared_ptr<A> parent)
    {
        this->parent = parent;
    }

private:
    std::shared_ptr<A> parent;
};

그러나 그 부름은 .shared_from_this() 하려면 시점에서 this소유 해야합니다 std::shared_ptr. 이것은 더 이상 스택에 이러한 객체를 만들 수 없으며 일반적으로.shared_from_this() 생성자 또는 소멸자 내에서 호출 할 수 없음을 의미합니다 .


1
귀하의 설명과 순환 종속성 문제를 지적 해 주셔서 감사합니다.
Icarus

@Deduplicator 무슨 뜻이야?
yuri kilochek

구축을 시도해보십시오 shared_ptr에 따라 기본 - 건설 shared_ptr및 당신이 무엇을 그것을 지적하고 싶어요 ...
Deduplicator

1
@Deduplicator는 내 말장난을 용서하고 오히려 무의미한 공유 포인터입니다. 이 생성자는 관리되는 개체의 멤버 또는 해당베이스에 대한 포인터와 함께 사용하기위한 것입니다. 어쨌든 당신의 요점은 무엇입니까 (미안합니다)? 이러한 비 소유 shared_ptr는이 질문과 관련이 없습니다. shared_from_this의 전제 조건 shared_ptr은 호출 시점 에 일부가 객체를 소유해야한다는 것을 명시합니다 .
yuri kilochek

1
바이 @kazarey 소유권은 shared_ptr호출의 시점에서 필요하지만 일반적인 사용 패턴에 같은 즉, 뭔가 shared_ptr<Foo> p(new Foo());, shared_ptr완전히 구축 된 후에 만 개체의 소유권을 가정합니다. shared_ptr생성자가 초기화 된 생성자 를 생성 하고 this로컬이 아닌 어딘가 (예 : 참조 인수)에 저장하여이를 피할 수 있으므로 생성자가 완료 될 때 죽지 않습니다. 그러나이 복잡한 시나리오는 필요하지 않을 것입니다.
yuri kilochek

9

스마트 포인터에 대한 오해에서 비롯된 것처럼 보이는 디자인에 몇 가지 문제가 있습니다.

스마트 포인터는 소유권을 선언하는 데 사용됩니다. 두 부모 모두 모든 자식을 소유하고 각 자식이 부모를 소유한다고 선언하여이를 깨뜨리는 것입니다. 둘 다 사실 일 수 없습니다.

또한 약한 포인터를 반환합니다. getChild() . 이렇게하면 호출자가 소유권에 대해 신경 쓰지 않아야한다고 선언하는 것입니다. 이제 이것은 매우 제한적일 수 있지만 그렇게함으로써 약한 포인터가 여전히 유지되는 동안 문제의 자식이 파괴되지 않도록해야합니다. 스마트 포인터를 사용하면 자체적으로 정렬됩니다. .

그리고 마지막으로. 일반적으로 새 엔티티를 수락 할 때 일반적으로 원시 포인터를 수락해야합니다. 스마트 포인터는 부모간에 자식을 교체하는 자체 의미를 가질 수 있지만 일반적인 사용을 위해서는 원시 포인터를 허용해야합니다.


스마트 포인터에 대한 이해를 명확히해야 할 것 같습니다. 지적 해주셔서 감사합니다.
Icarus
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.