어떤 C ++ 스마트 포인터 구현이 가능합니까?
비교, 장점, 단점 및 사용시기
이것은 가비지 수집 스레드 에서 분리 된 것으로, 간단한 답변이라고 생각한 것이 특정 스마트 포인터 구현에 대한 많은 의견을 생성했기 때문에 새로운 게시물을 시작할 가치가있는 것처럼 보였습니다.
궁극적으로 문제는 C ++에서 다양한 스마트 포인터 구현이 무엇이며 어떻게 비교합니까? 단순한 장단점 또는 예외 및 다른 방법으로 작동해야한다고 생각하는 것.
나는 내가 사용하거나 적어도 광택을 냈고 아래 답변으로 사용하는 것으로 간주되는 구현을 게시했으며 100 % 정확하지 않을 수도있는 차이점과 유사성에 대한 이해를 알고 있으므로 필요에 따라 사실을 확인하거나 자유롭게 수정하십시오.
목표는 일부 새로운 객체와 라이브러리에 대해 배우거나 이미 널리 사용되는 기존 구현에 대한 나의 사용법과 이해를 수정하고 다른 사람에 대한 적절한 참조로 끝나는 것입니다.
C ++ 03
std::auto_ptr
-아마도 최초의 드래프트 증후군으로 고통받은 원본 중 하나는 제한된 쓰레기 수거 시설 만 제공합니다. 첫 번째 단점은 delete
파괴로 인해 배열 할당 객체를 보유 할 수 없다는 것입니다 ( new[]
). 포인터의 소유권을 가지므로 두 개의 자동 포인터에는 동일한 객체가 포함되어서는 안됩니다. 할당은 소유권을 이전하고 rvalue 자동 포인터를 널 포인터로 재설정합니다 . 아마도 최악의 단점으로 이어질 것입니다. 위에서 언급 한 복사 불가능으로 인해 STL 컨테이너 내에서 사용할 수 없습니다. 모든 유스 케이스에 대한 최종 타격은 다음 C ++ 표준에서 더 이상 사용되지 않을 예정입니다.
std::auto_ptr_ref
-이것은 스마트 포인터가 아니며 실제로 std::auto_ptr
특정 상황에서 복사 및 할당을 허용하기 위해 함께 사용되는 디자인 세부 사항 입니다. 특히 소유권을 이전 하는 이동 생성자 로 알려진 Colvin-Gibbons 트릭을 사용하여 비 const std::auto_ptr
를 lvalue 로 변환하는 데 사용할 수 있습니다 .
반대로 std::auto_ptr
자동 가비지 수집을위한 범용 스마트 포인터로 사용되도록 의도 된 것은 아닙니다. 나의 제한된 이해와 가정의 대부분은 Herb Sutter의 auto_ptr의 효과적인 사용을 기반으로 하며 항상 가장 최적화 된 방식은 아니지만 정기적으로 사용합니다.
C ++ 11
std::unique_ptr
-이것은 대체 std::auto_ptr
할 친구입니다. std::auto_ptr
배열 작업, 개인 복사 생성자를 통한 lvalue 보호, STL 컨테이너 및 알고리즘과 함께 사용할 수있는 등 의 약점을 수정하기위한 주요 개선 사항을 제외하고는 상당히 유사합니다 . 성능 오버 헤드이기 때문에 메모리 풋 프린트가 제한되어 있으며 이는 원시 포인터를 소유하거나 대체로 묘사하기에 이상적인 후보입니다. "고유"는 암시 하듯이 이전과 마찬가지로 포인터 소유자가 한 명뿐입니다 std::auto_ptr
.
std::shared_ptr
-이것은 TR1을 기반으로 boost::shared_ptr
하지만 앨리어싱 및 포인터 산술을 포함하도록 개선되었습니다. 즉, 동적으로 할당 된 객체를 기준으로 계산 된 참조 스마트 포인터를 래핑합니다. "공유"는 마지막 공유 포인터의 마지막 참조가 범위를 벗어날 때 둘 이상의 공유 포인터가 포인터를 소유 할 수 있음을 의미하므로 개체가 적절하게 삭제됩니다. 이것들은 스레드로부터 안전하며 대부분의 경우 불완전한 유형을 처리 할 수 있습니다. 기본 할당자를 사용하여 하나의 힙 할당 std::make_shared
으로 효율적으로 구성하는 데 사용할 수 있습니다 std::shared_ptr
.
std::weak_ptr
-TR1과을 기반으로합니다 boost::weak_ptr
. 이것은 a가 소유 한 객체에 대한 참조 std::shared_ptr
이므로 std::shared_ptr
참조 카운트가 0으로 떨어지더라도 객체의 삭제를 막지 않습니다 . 원시 포인터에 액세스하려면 먼저 소유 한 포인터가 만료되어 이미 파괴 된 경우 빈을 반환하는 std::shared_ptr
을 호출 하여에 액세스해야합니다 . 이 방법은 여러 스마트 포인터를 사용할 때 무한한 중단 참조 횟수를 피하는 데 주로 유용합니다.lock
std::shared_ptr
후원
boost::shared_ptr
-가장 다양한 시나리오 (STL, PIMPL, RAII 등)에서 사용하기 가장 쉬운 방법은 공유 참조 카운트 스마트 포인터입니다. 어떤 상황에서는 성능과 오버 헤드에 대한 불만이 몇 번 들었지만, 그 주장이 무엇인지 기억할 수 없으므로 무시해야합니다. 분명히 그것은 계류중인 표준 C ++ 객체가 될만큼 인기가 있었고 스마트 포인터와 관련된 표준에 대한 단점은 없습니다.
boost::weak_ptr
- std::weak_ptr
이 구현을 기반으로 한 이전의 설명과 마찬가지로 이것은 소유하지 않은 참조를 허용합니다 boost::shared_ptr
. 놀랍게도 lock()
"강력한"공유 포인터에 액세스하기 위해 전화 를 걸지 않았 으며 이미 파괴되었을 수 있으므로 유효한지 확인해야합니다. 반환 된 공유 포인터를 저장하지 말고 포인터를 사용하자마자 범위를 벗어나도록하십시오. 그렇지 않으면 참조 횟수가 중단되고 객체가 파괴되지 않는 순환 참조 문제로 돌아갑니다.
boost::scoped_ptr
- This is a simple smart pointer class with little overhead probably designed for a better performing alternative to boost::shared_ptr
when usable. It's comparable to std::auto_ptr
especially in the fact that it can't be safely used as an element of a STL container or with multiple pointers to the same object.
boost::intrusive_ptr
- I've never used this but from my understanding it's designed to be used when creating your own smart pointer compatible classes. You need to implement the reference counting yourself, you'll also need to implement a few methods if you want your class to be generic, furthermore you'd have to implement your own thread safety. On the plus side this probably gives you the most custom way of picking and choosing exactly how much or how little "smartness" you want. intrusive_ptr
is typically more efficient than shared_ptr
since it allows you to have a single heap allocation per object. (thanks Arvid)
boost::shared_array
- This is a boost::shared_ptr
for arrays. Basically new []
, operator[]
, and of course delete []
are baked in. This can be used in STL containers and as far as I know does everything boost:shared_ptr
does although you can't use boost::weak_ptr
with these. You could however alternatively use a boost::shared_ptr<std::vector<>>
for similar functionality and to regain the ability to use boost::weak_ptr
for references.
boost::scoped_array
- This is a boost::scoped_ptr
for arrays. As with boost::shared_array
all the necessary array goodness is baked in. This one is non-copyable and so can't be used in STL containers. I've found almost anywhere you find yourself wanting to use this you probably could just use std::vector
. I've never determined which is actually faster or has less overhead but this scoped array seems far less involved than a STL vector. When you want to keep allocation on the stack consider boost::array
instead.
Qt
QPointer
- Introduced in Qt 4.0 this is a "weak" smart pointer which only works with QObject
and derived classes, which in the Qt framework is almost everything so that's not really a limitation. However there are limitations namely that it doesn't supply a "strong" pointer and although you can check if the underlying object is valid with isNull()
you could find your object being destroyed right after you pass that check especially in multi-threaded environments. Qt people consider this deprecated I believe.
QSharedDataPointer
- This is a "strong" smart pointer potentially comparable to boost::intrusive_ptr
although it has some built in thread safety but it does require you to include reference counting methods (ref
and deref
) which you can do by subclassing QSharedData
. As with much of Qt the objects are best used through ample inheritance and subclassing everything seems to be the intended design.
QExplicitlySharedDataPointer
- Very similar to QSharedDataPointer
except it doesn't implicitly call detach()
. I'd call this version 2.0 of QSharedDataPointer
as that slight increase in control as to exactly when to detach after the reference count drops to zero isn't particularly worth a whole new object.
QSharedPointer
- Atomic reference counting, thread safe, sharable pointer, custom deletes (array support), sounds like everything a smart pointer should be. This is what I primarily use as a smart pointer in Qt and I find it comparable with boost:shared_ptr
although probably significantly more overhead like many objects in Qt.
QWeakPointer
- Do you sense a reoccurring pattern? Just as std::weak_ptr
and boost::weak_ptr
this is used in conjunction with QSharedPointer
when you need references between two smart pointers that would otherwise cause your objects to never be deleted.
QScopedPointer
- This name should also look familiar and actually was in fact based on boost::scoped_ptr
unlike the Qt versions of shared and weak pointers. It functions to provide a single owner smart pointer without the overhead of QSharedPointer
which makes it more suitable for compatibility, exception safe code, and all the things you might use std::auto_ptr
or boost::scoped_ptr
for.
There is also Loki which implements policy-based smart pointers.
Other references on policy-based smart pointers, addressing the problem of the poor support of the empty base optimization along with multiple inheritance by many compilers:
- Smart Pointers Reloaded
- A Proposal to Add a Policy-Based Smart Pointer Framework to the Standard Library
In addition to the ones given, there are some safety oriented ones too:
SaferCPlusPlus
mse::TRefCountingPointer
is a reference counting smart pointer like std::shared_ptr
. The difference being that mse::TRefCountingPointer
is safer, smaller and faster, but does not have any thread safety mechanism. And it comes in "not null" and "fixed" (non-retargetable) versions that can be safely assumed to always be pointing to a validly allocated object. So basically, if your target object is shared among asynchronous threads then use std::shared_ptr
, otherwise mse::TRefCountingPointer
is more optimal.
mse::TScopeOwnerPointer
is similar to boost::scoped_ptr
, but works in conjunction with mse::TScopeFixedPointer
in a "strong-weak" pointer relationship kind of like std::shared_ptr
and std::weak_ptr
.
mse::TScopeFixedPointer
points to objects that are allocated on the stack, or whose "owning" pointer is allocated on the stack. It is (intentionally) limited in it's functionality to enhance compile-time safety with no runtime cost. The point of "scope" pointers is essentially to identify a set of circumstances that are simple and deterministic enough that no (runtime) safety mechanisms are necessary.
mse::TRegisteredPointer
behaves like a raw pointer, except that its value is automatically set to null_ptr when the target object is destroyed. It can be used as a general replacement for raw pointers in most situations. Like a raw pointer, it does not have any intrinsic thread safety. But in exchange it has no problem targeting objects allocated on the stack (and obtaining the corresponding performance benefit). When run-time checks are enabled, this pointer is safe from accessing invalid memory. Because mse::TRegisteredPointer
has the same behavior as a raw pointer when pointing to valid objects, it can be "disabled" (automatically replaced with the corresponding raw pointer) with a compile-time directive, allowing it to be used to help catch bugs in debug/test/beta modes while incurring no overhead cost in release mode.
Here is an article describing why and how to use them. (Note, shameless plug.)
참고URL : https://stackoverflow.com/questions/5026197/what-c-smart-pointer-implementations-are-available
'IT story' 카테고리의 다른 글
maven을 사용하는 경우 일반적으로 log4j.properties를 Java 또는 자원 아래에 배치합니까? (0) | 2020.07.13 |
---|---|
중복 된 MIME 유형“text / html”? (0) | 2020.07.13 |
뷰가 데이터베이스에 있는지 어떻게 확인합니까? (0) | 2020.07.12 |
제약 조건으로 열을 삭제하는 방법은 무엇입니까? (0) | 2020.07.12 |
MySQL 날짜 형식 DD / MM / YYYY 선택 쿼리? (0) | 2020.07.12 |