여기 에서 채택했습니다 .
C ++ 표준 라이브러리의 대부분 템플릿은 완전한 유형으로 인스턴스화해야합니다. 그러나 shared_ptr
하고 unique_ptr
있는 부분 예외. 모든 멤버가 아닌 일부 멤버는 불완전한 유형으로 인스턴스화 할 수 있습니다. 이에 대한 동기는 스마트 포인터를 사용한 pimpl 과 같은 관용구를 지원 하고 정의되지 않은 동작을 위험에 빠뜨리지 않는 것입니다.
불완전한 유형이 있고 호출 할 때 정의되지 않은 동작이 발생할 수 있습니다 delete
.
class A;
A* a = ...;
delete a;
위의 법률 코드입니다. 컴파일됩니다. 컴파일러는 위와 같은 위 코드에 대해 경고를 표시하거나 표시하지 않을 수 있습니다. 실행되면 나쁜 일이 발생합니다. 운이 좋으면 프로그램이 중단됩니다. 그러나 더 가능성이 높은 결과는 프로그램이 ~A()
호출되지 않는 한 자동으로 메모리를 누출한다는 것 입니다.
auto_ptr<A>
위 예제에서 사용하면 도움이되지 않습니다. 원시 포인터를 사용한 것처럼 여전히 정의되지 않은 동작이 발생합니다.
그럼에도 불구하고 특정 장소에서 불완전한 수업을 이용하는 것이 매우 유용합니다! 이것은 어디 shared_ptr
와 unique_ptr
도움이됩니다. 이 스마트 포인터 중 하나를 사용하면 완전한 유형이 필요한 경우를 제외하고 불완전한 유형으로 벗어날 수 있습니다. 그리고 가장 중요한 것은 완전한 유형이 필요한 경우, 그 시점에서 불완전한 유형의 스마트 포인터를 사용하려고하면 컴파일 타임 오류가 발생한다는 것입니다.
더 이상 정의되지 않은 동작 :
코드가 컴파일되면 필요한 모든 곳에서 완전한 유형을 사용했습니다.
class A
{
class impl;
std::unique_ptr<impl> ptr_; // ok!
public:
A();
~A();
// ...
};
shared_ptr
및 unique_ptr
다른 장소에서 완전한 형태를 필요로한다. 동적 삭제 기와 정적 삭제와 관련이있는 이유는 명확하지 않습니다. 정확한 이유는 중요하지 않습니다. 실제로 대부분의 코드에서 완전한 유형이 필요한 위치를 정확히 아는 것은 중요하지 않습니다. 코드 만 작성하면 잘못되면 컴파일러에서 알려줍니다.
그러나 경우에, 여기 당신에게 도움이되는 여러 회원 문서화 테이블입니다 shared_ptr
및 unique_ptr
완전성 요구 사항에 대한이. 멤버에 완전한 유형이 필요한 경우 항목에 "C"가 있고 그렇지 않으면 테이블 항목이 "I"로 채워집니다.
Complete type requirements for unique_ptr and shared_ptr
unique_ptr shared_ptr
+------------------------+---------------+---------------+
| P() | I | I |
| default constructor | | |
+------------------------+---------------+---------------+
| P(const P&) | N/A | I |
| copy constructor | | |
+------------------------+---------------+---------------+
| P(P&&) | I | I |
| move constructor | | |
+------------------------+---------------+---------------+
| ~P() | C | I |
| destructor | | |
+------------------------+---------------+---------------+
| P(A*) | I | C |
+------------------------+---------------+---------------+
| operator=(const P&) | N/A | I |
| copy assignment | | |
+------------------------+---------------+---------------+
| operator=(P&&) | C | I |
| move assignment | | |
+------------------------+---------------+---------------+
| reset() | C | I |
+------------------------+---------------+---------------+
| reset(A*) | C | C |
+------------------------+---------------+---------------+
포인터 변환이 필요한 모든 작업에는 unique_ptr
및에 대한 완전한 유형이 필요합니다 shared_ptr
.
unique_ptr<A>{A*}
생성자는 멀리 얻을 수 불완전 A
단지 컴파일러에 대한 호출을 설정하는 데 필요하지 않은 경우 ~unique_ptr<A>()
. 예를 들어 unique_ptr
, 힙 을두면 불완전한 상태로 벗어날 수 있습니다 A
. 이 지점에 대한 자세한 내용은 BarryTheHatchet의 답변 here 에서 찾을 수 있습니다 .
shared_ptr
/unique_ptr
" 입니다.