일부 C++ 11 std::unique_ptr
사용 및 gotchas 무엇입니까?일부 std :: unique_ptr 사용 및 "gotchas"
std::unique_ptr
도 동적으로 할당 된 배열을 저장할 수 있습니까?
std::unique_ptr
을 사용자 지정 삭제 메커니즘을 사용하는 리소스와 함께 사용할 수 있습니까?
일부 C++ 11 std::unique_ptr
사용 및 gotchas 무엇입니까?일부 std :: unique_ptr 사용 및 "gotchas"
std::unique_ptr
도 동적으로 할당 된 배열을 저장할 수 있습니까?
std::unique_ptr
을 사용자 지정 삭제 메커니즘을 사용하는 리소스와 함께 사용할 수 있습니까?
Q & A 형식을 사용하여 몇 가지 용도와 기능을 정리해 보겠습니다.
Q1 : 나는 내 수업 X
내부 클래스 Component
에 포인터를 저장하고 싶습니다.
"컨테이너"클래스 X
을 복사 할 수 없습니다. X
은 Component
인스턴스의 유일한 소유자입니다.
나는 소유원시 포인터가 나쁜 일 및 "leaktrocities"의 잠재적 인 소스입니다 ( 원시 포인터를 관찰하는 대신 괜찮) 것을 알고있다. 무엇을 스마트 포인터이 목적으로 사용할 수 있습니까? A1
: C++ (11)의 std::unique_ptr
확실히 좋은 방법입니다.
고유 한 (비공유) 소유권의 경우에는 문제가 없으며 std::shared_ptr
의 오버 헤드가 없습니다.
이전 C++ 98/03 boost::scoped_ptr
에 대한 탁월한 대체품입니다.
사실, 또한 std::unique_ptr
은 이동 의미을 제공합니다.
X
에 unique_ptr<Component>
데이터 멤버 (및 기타 이동 가능 데이터 멤버)가 포함 된 경우 전체 클래스 X
은 이 자동으로이됩니다.
#include <memory> // for std::unique_ptr
class X
{
std::unique_ptr<Component> m_pComponent;
....
public:
X()
: m_pComponent(new Component())
{
....
}
}
(. 물론, 스마트 포인터되고, 명시 적으로 포함하는 클래스의 소멸자에서 삭제 할 필요가 없습니다)
:
예 사용은 아래로 보여 질문 2 : 대단합니다! 명시 적 소멸자가 필요없고, 아무런 덧씌우개가 필요 없습니다. (일반적인 C++ 철학 : "우리가 사용하지 않는 것에 대해서는 돈을 내지 않습니다"), 이미 구현 된 의미 체계를 옮깁니다!
그러나 문제가 있습니다. 내 클래스 Component
에 생성자 오버로드가있어서 Component
인스턴스를 만들기 전에 생성자 코드에서 계산해야하는 매개 변수가 필요합니다.나는 unique_ptr
새로 만든 Component
을 지정 생성자에서 통상의 operator=
의 할당은을 사용하여 시도,하지만 오류 메시지가 있어요 :
X::X()
{
....
const int param = CalculateCoolParameter();
// This assignment fails:
m_pComponent = new Component(param); // <---- Error pointing to '=' here
^--- error
}
A2 : OK, 아마 당신이 기대했던 이전의 해제 operator=
과부하가 소유를 포인터 (있는 경우)와 새로 생성 된 포인터에 할당합니다.
불행히도 이러한 과부하는 없습니다.
그러나 std::unique_ptr::reset()
방법을 사용합니다.
m_pComponent.reset(new Component(param));
Q3 : 이봐! 이 unique_ptr
정말 멋지다! 나는 그것이 영리하다는 것을 좋아한다, 그것은 자동적으로 움직일 수 있고, 머리 위를 가져 오지 않는다.
그래서 std::vector
을 사용하는 대신 동적으로 할당 된 배열 (런타임시 계산 됨)을 저장하고 싶습니다. (코드의이 부분에서 나는 매우 제한적이며, 그렇지 않습니다. 모든 std::vector
의 동적 크기 조정 기능, 딥 복사 등을 원하지 않기 때문에 std:vector
오버 헤드 비용을 지불하고 싶습니다. 대신 내가 count
소멸자 호출을 예상
const size_t count = GetComponentsCount();
unique_ptr<Component> components(new Component[count]);
그것은 잘 컴파일,하지만 난 ~Component
소멸자 만 번라고 주목 :
나는 이런 식으로 뭔가를 시도! 여기서 뭐가 잘못 됐어?
A3
: 문제는 상기 구문,std::unique_ptr
할당 된 객체를 방출 delete
를 사용한다는 것이다. 그러나 이들이 new[]
을 사용하여 할당되었으므로 올바른 정리 전화는 delete[]
(괄호가없는 delete
이 아님)입니다. 이 문제를 해결하려면 제대로 리소스를 해제하기위한 delete[]
를 사용하는 unique_ptr
를 지시는 다음 구문을 사용해야합니다 :
unique_ptr<Component[]> components(new Components[count]);
// ^^
//
// Note brackets "[]" after the first occurrence of "Component"
// in unique_ptr template argument.
//
Q4 : 좋아요! 그러나 나는 (fopen()
연) C <stdio.h>
파일 fclose()
, 또는 CloseHandle()
처럼, 자원 해제 코드가 일부 사용자 정의 정리 기능를 사용하는 대신 일반 C++ delete
(또는 delete[]
)를 사용하지만, 수행되지 않는 경우에 unique_ptr
도 사용할 수 있습니다 Win32 파일 HANDLE
(CreateFile()
을 사용하여 생성)에 대해?
A4는 : 그것은 확실히 가능합니다 : 당신이 std::unique_ptr
에 대한 사용자 정의 Deleter가을 지정할 수 있습니다.
:
//
// Custom deleter function for FILE*: fclose().
//
std::unique_ptr<FILE, // <-- the wrapped raw pointer type: FILE*
int(*)(FILE*)> // <-- the custom deleter type: fclose() prototype
myFile(fopen("myfile", "rb"), // <-- resource (FILE*) is returned by fopen()
fclose); // <-- the deleter function: fclose()
//
// Custom deleter functor for Win32 HANDLE: calls CloseHandle().
//
struct CloseHandleDeleter
{
// The following pointer typedef is required, since
// the raw resource is HANDLE (not HANDLE*).
typedef HANDLE pointer;
// Custom deleter: calls CloseHandle().
void operator()(HANDLE handle) const
{
CloseHandle(handle);
}
};
std::unique_ptr<HANDLE, CloseHandleDeleter> myFile(CreateFile(....));
FWIW, 사용하지 않는 벡터 기능에 대해 어떻게 지불합니까? (힌트 : 아무 것도) –
적어도 메모리 풋 프린트로부터,'std :: vector'는 3 개의 포인터를 사용할 수 있습니다. 대신에 'unique_ptr' 하나만 사용할 수 있습니다. –
A2 : 가능한 한 더 좋은 해결책은 계산을 수행하고 std :: unique_ptr을 반환하는 메서드를 갖는 것입니다. 그런 다음 이니셜 라이저 목록에서 해당 값을 사용하십시오. – stijn