unique_ptr <Derived>가 unique_ptr <Base>에 암시 적으로 캐스트되는 이유는 무엇입니까?


21

예상되는 unique_ptr<Derived>위치 를 사용하는 다음 코드를 작성했습니다.unique_ptr<Base>

class Base {
    int i;
 public:
    Base( int i ) : i(i) {}
    int getI() const { return i; }
};

class Derived : public Base {
    float f;
 public:
    Derived( int i, float f ) : Base(i), f(f) {}
    float getF() const { return f; }
};

void printBase( unique_ptr<Base> base )
{
    cout << "f: " << base->getI() << endl;
}

unique_ptr<Base> makeBase()
{
    return make_unique<Derived>( 2, 3.0f );
}

unique_ptr<Derived> makeDerived()
{
    return make_unique<Derived>( 2, 3.0f );
}

int main( int argc, char * argv [] )
{
    unique_ptr<Base> base1 = makeBase();
    unique_ptr<Base> base2 = makeDerived();
    printBase( make_unique<Derived>( 2, 3.0f ) );

    return 0;
}

나의 이해에 따라 때문에 내가 컴파일하지에이 코드를 기대 unique_ptr<Base>하고하는 것은 unique_ptr<Derived>관련이없는 종류와 unique_ptr<Derived>에서 파생 된 사실에없는 unique_ptr<Base>할당이 작업 안 그렇게.

그러나 어떤 마술 덕분에 효과가 있으며, 왜, 또는 그렇게하는 것이 안전한지 이해하지 못합니다. 누군가 설명해 주시겠습니까?


3
스마트 포인터는 포인터가 제한 할 수없는 것을 풍부하게합니다. 이것이 가능 unique_ptr하지 않다면 상속 이 있을 때 오히려 쓸모가 없을 것입니다
idclev 463035818

3
"하지만 어떤 마법 덕분에 작동합니다 . " 거의 Base가상 소멸자가 없으므로 UB 가 있습니다.
Jarod42

답변:


25

당신이 찾고있는 마법의 비트는 변환 생성자 # 6입니다 여기 :

template<class U, class E>
unique_ptr(unique_ptr<U, E> &&u) noexcept;

std::unique_ptr<T>만료되는 std::unique_ptr<U> if (명확하게하기 위해 deleters에 광택 있음) 에서 암시 적으로 구성 할 수 있습니다 .

unique_ptr<U, E>::pointer 묵시적으로 pointer

즉, 파생-대-기반 변환을 포함하여 암시 적 원시 포인터 변환을 모방하고 예상 수명을 기준으로 안전하게 수행합니다 (여전히 기본 유형을 다형성으로 삭제할 수 있는지 확인해야 함).


2
AFAIK의 Base삭제자가의 소멸자를 호출 Derived하지 않으므로 실제로 안전한지 확실하지 않습니다. (그것은 틀림없이, 원시 포인터보다 덜 안전하지 않습니다.)
cpplearner

14

왜냐하면 std::unique_ptrA 변환 등이있다 생성자

template< class U, class E >
unique_ptr( unique_ptr<U, E>&& u ) noexcept;

이 생성자는 다음 사항이 모두 충족되는 경우에만 과부하 해결에 참여합니다.

a) unique_ptr<U, E>::pointer암시 적으로pointer

...

A Derived*Base*암시 적으로 변환 할 수 있으며이 경우 변환 생성자를 적용 할 수 있습니다. 그런 다음 원시 포인터처럼 암시 적 std::unique_ptr<Base>으로 a를 변환 할 수 있습니다 std::unique_ptr<Derived>. ( 의 특성으로 인해 std::unique_ptr<Derived>생성을 위해서는 rvalue 여야합니다 .)std::unique_ptr<Base>std::unique_ptr


7

당신은 할 수 암시 적 구성체 std::unique_ptr<T>에서 인스턴스 를 rvaluestd::unique_ptr<S>때마다 S로 변환입니다 T. 이 # 6 생성자 예정이다 여기 . 이 경우 소유권이 이전됩니다.

귀하의 예에서는 rvalues ​​유형 std::uinque_ptr<Derived>( r 값이 std::make_uniquervalue 이기 때문에) 만 가지고 있으며,이를 값으로 사용할 때 std::unique_ptr<Base>위에서 언급 한 생성자가 호출됩니다. std::unique_ptr<Derived>따라서 문제 의 대상은 짧은 시간 동안 만 존재합니다. 즉, 대상이 생성 된 후 소유권이std::unique_ptr<Base> 객체 이후에 사용되는 객체 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.