사용의 장점은 std::unique_ptr<T>
(호출 delete
하거나 delete[]
명시 적으로 기억할 필요가 없다는 점을 제외하고 ) 포인터가 nullptr
(기본) 개체의 유효한 인스턴스 중 하나 이거나 가리키는 것을 보장한다는 것 입니다. 나는 귀하의 질문에 대답 후 나는이 다시 올 것이다,하지만 첫 번째 메시지는 DO가 동적으로 할당 된 개체의 수명을 관리하는 스마트 포인터를 사용합니다.
이제 문제 는 실제로 이전 코드에서 이것을 사용하는 방법 입니다.
내 제안은 소유권을 이전하거나 공유하지 않으려면 항상 객체에 대한 참조를 전달 해야한다는 것 입니다. 다음과 같이 함수를 선언하십시오 ( const
필요에 따라 한정자 가 있거나 없음 ).
bool func(BaseClass& ref, int other_arg) { ... }
그런 다음 std::shared_ptr<BaseClass> ptr
의지 가있는 호출자 는 nullptr
케이스 를 처리 하거나 bool func(...)
결과 계산 을 요청 합니다.
if (ptr) {
result = func(*ptr, some_int);
} else {
}
이는 모든 호출자가 참조가 유효하며 함수 본문 실행 내내 계속 유효하다는 것을 약속 해야 함을 의미합니다 .
여기에 내가 강력하게한다고 생각하는 이유입니다 하지 스마트 포인터 원시 포인터 또는 참조를 전달합니다.
원시 포인터는 메모리 주소 일뿐입니다. (적어도) 4 가지 의미 중 하나를 가질 수 있습니다.
- 원하는 개체가있는 메모리 블록의 주소입니다. ( 좋은 )
- 확신 할 수있는 주소 0x0은 역 참조 할 수 없으며 "nothing"또는 "no object"의 의미를 가질 수 있습니다. ( 나쁜 )
- 프로세스의 주소 지정 가능 공간 밖에있는 메모리 블록의 주소입니다 (해석을 해제하면 프로그램이 중단 될 수 있습니다). ( 못생긴 )
- 역 참조 할 수 있지만 예상 한 내용을 포함하지 않는 메모리 블록의 주소입니다. 포인터가 실수로 수정되어 이제 다른 쓰기 가능한 주소 (프로세스 내의 완전히 다른 변수)를 가리킬 수 있습니다. 이 메모리 위치에 쓰는 것은 당신이 거기에 쓸 수있는 한 OS가 불평하지 않기 때문에 실행 중에 때때로 많은 재미를 유발할 것입니다. ( Zoinks! )
스마트 포인터를 올바르게 사용하면 일반적으로 컴파일 타임에 감지 할 수없고 일반적으로 프로그램이 충돌하거나 예상치 못한 일을 수행 할 때 런타임에만 경험하는 다소 무서운 사례 3과 4를 완화합니다.
스마트 포인터를 인수로 전달하는 const
데는 두 가지 단점이 있습니다 . 복사본을 만들지 않고 는 뾰족한 개체 의 -ness를 변경할 수 없으며 (에 대해 오버 헤드를 추가 shared_ptr
하고 가능하지 않음 unique_ptr
) 여전히 두 번째 ( nullptr
) 의미 가 남아 있습니다.
디자인 관점에서 두 번째 사례를 ( 나쁜 ) 으로 표시했습니다 . 이것은 책임에 대한 더 미묘한 주장입니다.
함수 nullptr
가 매개 변수로 a 를 수신 할 때 의미하는 바를 상상해보십시오 . 먼저 무엇을할지 결정해야합니다. 누락 된 개체 대신 "마법적인"값을 사용합니까? 동작을 완전히 변경하고 다른 것을 계산합니까 (객체가 필요하지 않음)? 당황하고 예외를 던지시겠습니까? 또한 함수가 원시 포인터로 2 개 또는 3 개 이상의 인수를 취하면 어떻게됩니까? 각각을 확인하고 그에 따라 동작을 조정해야합니다. 이것은 실제 이유없이 입력 유효성 검사에 완전히 새로운 수준을 추가합니다.
발신자는 이러한 결정을 내릴 수있는 충분한 상황 정보를 가진 사람이어야합니다. 즉, 더 많이 알수록 나쁜 것은 덜 두렵습니다. 반면에이 함수는 가리키는 메모리가 의도 한대로 작업하기에 안전하다는 호출자의 약속을 받아 들여야합니다. (참조는 여전히 메모리 주소이지만 개념적으로 유효성에 대한 약속을 나타냅니다.)
std::unique_ptr
은std::vector<std::unique_ptr>
논쟁 을 위해 없애 버려 ?