[c++] shared_ptr <Derived>를 shared_ptr <Base>로 전달

shared_ptr파생 유형을 shared_ptr기본 유형 을 취하는 함수 에 전달하는 가장 좋은 방법은 무엇입니까 ?

나는 일반적으로 shared_ptr불필요한 사본을 피하기 위해 s를 참조로 전달합니다 .

int foo(const shared_ptr<bar>& ptr);

하지만 다음과 같은 작업을 시도하면 작동하지 않습니다.

int foo(const shared_ptr<Base>& ptr);

...

shared_ptr<Derived> bar = make_shared<Derived>();
foo(bar);

나는 사용할 수있다

foo(dynamic_pointer_cast<Base, Derived>(bar));

그러나 이것은 두 가지 이유로 차선책으로 보입니다.

  • A dynamic_cast는 단순한 파생에서 기본 캐스트에 대해 약간 과도하게 보입니다.
  • 내가 이해했듯이 dynamic_pointer_cast함수에 전달할 포인터의 복사본 (임시적이긴하지만)을 만듭니다.

더 나은 해결책이 있습니까?

후손을위한 업데이트 :

누락 된 헤더 파일 문제로 판명되었습니다. 또한 여기서 제가하려는 것은 반 패턴으로 간주됩니다. 일반적으로,

  • 객체의 수명에 영향을주지 않는 함수 (즉, 객체가 함수 기간 동안 유효 함)는 일반 참조 또는 포인터를 가져야합니다 (예 : int foo(bar& b).

  • 객체 를 소비 하는 함수 (즉, 주어진 객체의 최종 사용자)는 unique_ptr값 (예 :)을 가져야합니다 int foo(unique_ptr<bar> b). 호출자는 std::move함수에 값을 입력해야합니다.

  • 객체의 수명을 연장하는 함수는 shared_ptr예를 들어 int foo(shared_ptr<bar> b). 순환 참조 를 피하기위한 일반적인 조언이 적용됩니다.

자세한 내용은 Herb Sutter의 Back to Basics 토크 를 참조하십시오.



답변

BaseDerived공변 이더라도 그들에 대한 원시 포인터는 그에 따라 작동 shared_ptr<Base>하며 공변 shared_ptr<Derived>아닙니다 . 는 dynamic_pointer_cast이 문제를 처리 할 수있는 정확하고 간단한 방법입니다.

( 편집 : static_pointer_cast 파생에서 기본으로 캐스팅하므로 안전하고 런타임 검사가 필요하지 않으므로 더 적합합니다. 아래 주석을 참조하십시오.)

그러나 foo()함수가 수명 연장에 참여하지 않으려는 경우 (또는 객체의 공유 소유권에 참여하는 대신) 를 전달할 때 를 수락 const Base&하고 역 참조하는 것이 가장 좋습니다 .shared_ptrfoo()

void foo(const Base& base);
[...]
shared_ptr<Derived> spDerived = getDerived();
foo(*spDerived);

제쳐두고, shared_ptr유형은 공변이 될 수 없기 때문에 공변 반환 유형에 대한 암시 적 변환 규칙은의 유형을 반환 할 때 적용되지 않습니다 shared_ptr<T>.


답변

파생 클래스에 대해 공용 상속 을 지정하는 것을 잊은 경우에도 마찬가지입니다. 즉, 저처럼 다음과 같이 작성합니다.

class Derived : Base
{
};


답변

너무 열심히 노력하는 것 같습니다. shared_ptr복사하기가 저렴합니다. 그것이 목표 중 하나입니다. 참조로 전달하는 것은 실제로 많은 것을 성취하지 못합니다. 공유하지 않으려면 원시 포인터를 전달하십시오.

즉, 머리 위에서 생각할 수있는 두 가지 방법이 있습니다.

foo(shared_ptr<Base>(bar));
foo(static_pointer_cast<Base>(bar));


답변

또한 #include파생 클래스의 전체 선언을 포함하는 헤더 파일의가 소스 파일에 있는지 확인하십시오.

나는이 문제가 있었다. 은 std::shared<derived>에 캐스팅 않을 것이다 std::shared<base>. 나는 그들에 대한 포인터를 보유 할 수 있도록 두 클래스를 앞으로 선언했지만 #include컴파일러가 없었기 때문에 한 클래스가 다른 클래스에서 파생되었음을 알 수 없었습니다.


답변