2012-03-14 3 views
45

기존 코드를 "현대화"하려고합니다.unique_ptr을 함수에 전달

  • 현재 회원 변수가 "Device * device_"인 수업이 있습니다.
  • 새로운 초기화 코드에서 인스턴스를 생성하기 위해 new를 사용하고, destructory에 "delete device_"가 있습니다.
  • 이 클래스의 멤버 함수는 많은 Device *를 매개 변수로 사용하는 다른 함수를 호출합니다.
  • 이 있지만, 잘 작동

내 코드는 내가 "std::unique_ptr<Device> device_"로 정의 할 수있는 변수를 변경하고 코드를 안전하고 일반적으로 더 나은하게 삭제하는 명시 적으로 호출을 제거한다고 생각했다 "현대화".

  • 가 어떻게 다음 paramater로 필요로하는 모든 기능에 장치 _ 변수를 전달해야한다 -

    내 질문은 이것이다?

각 함수 호출에서 .get을 호출하여 .get을 호출 할 수 있습니다. 그러나 그것은 추악한 것처럼 보이고 처음에는 unique_ptr을 사용하는 몇 가지 이유를 낭비합니다.

또는 대신 유형의 매개 변수 "장치 *"를 복용 지금 "& unique_ptr 표준 :"유형의 paramater 발생하도록 나는 마다 기능을 변경할 수 있습니다. 어느 것이 (나에게) 함수 프로토 타입을 다소 난독 화하고 읽기 어렵게 만듭니다.

가장 좋은 방법은 무엇입니까? 다른 옵션을 놓친 적이 있습니까?

+3

왜이 변경 코드가 안전하고 일반적으로 더 나은 만들 것 패스? 당신의 설명에서, 나는 그 반대가 사실이라고 말할 것입니다. –

+0

@James Kanze 나는이 경우 unique_ptr이 아무 것도 사지 않는 것 같아. – juanchopanza

+2

당신이 옳을 수도 있습니다. unique_ptr의 "안전성"이 마음에 들지만 삭제할 필요가 없다는 점에서이 경우에는 비용이들 것 같습니다. – jcoder

답변

44

현대 C++ 스타일에서 두 개의 키 개념이 있습니다 :

  • 무효

    • 소유권

    소유권이 경우 (일부 개체/자원의 소유자에 관한 것입니다 , Device의 인스턴스). 다양한 std::unique_ptr, boost::scoped_ptr 또는 std::shared_ptr은 소유권과 관련이 있습니다.

    Nullity은 단순하지만 주어진 객체가 null 일 수 있는지 여부를 표현하고 다른 것에는 관심이없고 소유권에 대해서는 신경 쓰지 않습니다.


    당신은 당신이 깊은 복사 의미와 스마트 포인터를 할 수 있지만 당신의 목표는 PIMPL을 구현하는 경우, (일반적으로) unique_ptr 향해 클래스의 구현을 이동 오른쪽이었다.

    이것은 분명히 클래스가이 메모리를 담당하는 유일한 책임이며 메모리가 누출되었을 수있는 다양한 방법을 모두 처리한다는 것을 분명히 전합니다. 한편


    , 대부분의 사용자는 자원의는 소유권에 대해 덜 신경 수 없었다.

    함수가 객체에 대한 참조를 유지하지 않는 한 (지도 또는 무언가에 저장하는 경우) 중요한 것은 객체의 수명이 함수 호출 기간을 초과한다는 것입니다.

    따라서, 어떻게 통과하는 선택 매개 변수는 가능 무효에 따라 달라집니다 : 절대 널 (null)

    • 를? 참조
    • 아마도 null일까요?포인터, 간단한 맨손으로 포인터 나 (예를 들어 널 (null)에 트랩) 포인터와 같은 클래스

  • +0

    흠, 참고 문헌 ... 필자의 함수가 "Device & device"매개 변수를 사용하도록 만들 수 있고 호출 코드에서 * device_이 여전히 unique_ptr과 함께 작동하므로 device_가 널이 될 수 없다는 것을 알고 (assert로 테스트 할 수 있습니다.) 이제 조금 숙고 해 추악하고 우아한 지 결정해야합니다. – jcoder

    +2

    @ JohnB : 글쎄요, 필자의 관점은 컴파일 타임에 무효 가능성을 제거하는 것이 훨씬 안전하다는 것입니다. –

    +6

    @JohnB : 여기 Matthieu에 완전히 동의하며, 앞으로 나아갈 것입니다. 왜 동적으로 원하는가? 수명을 포인터를 보유하고있는 객체의 수명으로 묶는 객체를 할당합니까? 자동 저장 기능을 가진 일반 멤버로 선언하는 것이 어떻습니까? –

    7

    나는 std::unique_ptr const&을 사용할 것입니다. 비 const 레퍼런스를 사용하면 호출 된 함수에 포인터를 재설정 할 수 있습니다.
    나는 이것이 당신의 호출 된 함수가 포인터를 사용할 수 있지만 다른 것은 사용할 수 없다는 것을 표현하는 좋은 방법이라고 생각한다.
    그래서 나를 위해이 인터페이스를 쉽게 읽을 수 있습니다. 나는 포인터가 나에게 전달되면서 주변을 두들 할 필요가 없다는 것을 안다.

    +0

    그래서 분명히 const를 추가하면 어떤 식 으로든 unique_ptr을 변경할 수 없지만 unique_ptr을 통해 포함 된 객체의 비 const 함수를 호출 할 수 있습니까? – jcoder

    +0

    @ JohnB : 예, const는 호출 된 함수가 unique_ptr을 호출하는 등의 방지합니다. 하지만 포인터가 내부적으로 const가 아닌 한 non const 함수를 호출 할 수 있습니다. – mkaes

    +0

    가능합니다. unique_ptr의 get() const 메소드는 unique_ptr에 의해 지켜지는 객체에 대한 non-const 포인터를 반환합니다. – zabulus

    1

    그럴 수는 없지만 모든 경우를 Device*으로 바꿔 const unique_ptr<Device>&으로 바꾸는 것이 좋습니다.

    분명히 unique_ptr을 복사 할 수 없으므로 이동하지 않으셔도됩니다. unique_ptr에 대한 참조로 대체하면 기존 함수 본문의 본문이 계속 작동 할 수 있습니다.

    이제 함정이있어서 unique_ptr.reset() 또는 unique_ptr().release()을 피하기 위해 const &을 통과해야합니다. 여전히 수정 가능한 포인터가 장치에 전달됩니다. 이 솔루션을 사용하면 포인터 또는 참조를 const Device에 전달하는 쉬운 방법이 없습니다.

    +0

    const unique_ptr & 다루기 힘들 기 때문에 Device_t 또는 그와 유사한 것으로 typedef합니다. –

    14

    정말 다릅니다. 함수가 unique_ptr의 소유권을 가져야하는 경우 서명은 unique_ptr<Device> bv 이고 호출자는 std::move 포인터 여야합니다. 소유권 문제가 아니라면 원시 포인터 서명을 유지하고 get()을 사용하여 unique_ptr 포인터를 전달합니다. 이것은 추한 것이 아닙니다 해당 기능이 소유권을 넘기지 않는 경우.

    +0

    예 저는 소유권을 갖고 싶지 않습니다. 단지 함수에서 가리키는 것을 사용하십시오. – jcoder

    +2

    소유권이 문제가 아닌 경우 unique_ptr에 대한 const 참조를 전달할 수도 있습니다. 어떤 사람들은 Pascals의 in-out 형식 매개 변수 의미 (Google C++ 스타일 가이드)를 시뮬레이트하기 위해 포인터 참조 이분법을 사용합니다. –

    2

    이 경우에는 std::unique_ptr이 아닌 경우를 사용하는 것이 가장 좋습니다. (보통 은 클래스의 동적 할당 객체에 대한 포인터가 아닙니다.이 경우에도 이 달려 있습니다.)이 경우에 수행하고 싶지 않은 것은 입니다. std::unique_ptr (및 당신은 눈치 채 셨습니다, std::unique_ptr<> const&은 약간 다루기 힘들고 난독 화됩니다.) 이 이 개체에 동적으로 할당 된 유일한 포인터 인 경우, 난 원시 포인터로 을 붙이고, 소멸자에는 delete을 붙이면됩니다. 이러한 포인터가 있다면, 나는 그들 각각을 별도의 기본 클래스 (그들은 여전히 ​​원시 포인터가 될 수있는 곳)로 강등시키는 것을 고려할 것입니다.