39

Does C++11 have something equivalent to boost::intrusive_ptr?

My problem is that I have a C-style interface over my C++ code. Both sides of the interface can use C++, but exposing the C interface is required for compatibility reasons. I cannot use std::shared_ptr because I have to manage the object through two (or more) smart pointers. I am unable to figure out a solution with something like boost::intrusive_ptr.

Jeffrey Bosboom
  • 13,313
  • 16
  • 79
  • 92
Aarkan
  • 3,811
  • 6
  • 40
  • 54
  • You can make an `intrusive_ptr` implementation using a wrapper around `unique_ptr` with a custom deleter, allowing you to make a thread safe (or not) reference count. It's not as easy to pass around (requires moving, or manually manipulating the ref count), but is possible. – Chad Oct 11 '16 at 23:56

1 Answers1

53

Does c++11 have something equivalent to boost::intrusive_ptr?

No.

It does have std::make_shared which means std::shared_ptr is almost (see note below) as efficient as an intrusive smart pointer, because the reference counts will be stored adjacent in memory to the object itself, improving locality of reference and cache usage. It also provides std::enable_shared_from_this which allows you to retrieve a std::shared_ptr when you only have a built-in pointer to an object owned by a shared_ptr, but that doesn't allow you to manage the object using different smart pointer types.

shared_ptr expects to be entirely responsible for managing the object. A different smart pointer type might only manage the "strong" refcount and not the "weak" refcount, which would allow the counts to get out of sync and break the invariants of shared_ptr.


Note: Using make_shared allows shared_ptr to be almost as efficient as an intrusive pointer. The object and the reference counting info can be allocated in a single chunk of memory when make_shared is used, but there will still be two reference counts (for the "strong" and "weak" counts) which isn't the case for intrusive pointers as they don't support a weak_ptr. Also, the shared_ptr object itself always has to store two pointers (the one that will be returned by shared_ptr::get() and another pointer to the "control block" that contains the reference counts and knows the dynamic type of the owned object) so has a larger footprint than an intrusive pointer.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • 13
    _intrusive pointers that don't support a weak_ptr_ - To clarify: Intrusive pointers cannot support (thread-safe) weak_ptr by design. The refcount needs to be stored outside the object, otherwise any lock attempt on a weak pointer would race with the destruction of the object. In other words: Each weak pointer has shared ownership on the refcount. So if the refcounter is inseparable from the object itself (as is the case with an intrusive pointer), the weak pointer hence also has (strong) shared ownership on the object itself, which contradicts the concept of a weak pointer. – ComicSansMS May 06 '14 at 14:52
  • 1
    @ComicSansMS, indeed - that was poor wording on my part. I've reworded the note slightly and I hope it's clearer. Thanks. – Jonathan Wakely May 06 '14 at 15:12
  • 3
    @ComicSansMS it is not just a problem with threads: weak pointers cannot check if the object is still alive because if it has been destructed already they would read `free`d memory – pqnet Aug 11 '14 at 12:17
  • You could also store references to all weak pointers and clear them on destruction, i.e. the behavious Qt's QPointer (although impl might be different). – Macke Aug 20 '14 at 08:31
  • 3
    `shared_ptr` violates the "you don't pay for the what you don't use" principle. It stores at least two counters plus a deleter (at least four words in total?), plus the size of every `shared_ptr` is two words instead of one. This is quite a lot to pay for linked structures with small nodes where weak references aren't needed. (Think of a rope implementation) – Yakov Galka May 07 '15 at 14:11
  • It's much more space efficient because a shared pointer is 2 pointer and an intrusive_ptr is just one. – Lothar Dec 30 '17 at 06:35
  • 6
    @ybungalobill "you don't pay for the what you don't use" doesn't apply for picking the wrong tool for the job. If you *don't* need shared ownership, don't use `shared_ptr`. – Caleth Dec 03 '18 at 14:37
  • @Caleth Most often I seem to need shared ownership without a custom deleter and without the need for weak pointer support. Which (standard) tool other than `shared_ptr` should I use? – user686249 Dec 02 '21 at 10:22
  • @user686249 do you need shared ownership, or would one owner and many non-owning pointers suffice? The latter is far more common ime. The owner can be a container, or automatic duration storage, it need not be `std::unique_ptr` – Caleth Dec 02 '21 at 11:48
  • @Caleth Yes, of course, exclusive ownership is by far the most common, but when I need shared ownership, I often don't need a custom deleter and virtually never `weak_ptr` support. I still pay for both features, however, when using `shared_ptr`. I'm referring to your suggestion, that `shared_ptr` might be the wrong tool for the job. I'm just unaware of any (standard) alternative. – user686249 Dec 02 '21 at 15:13
  • @user686249 The weak count does take up space even if you don't need it, but how do you pay for a custom deleter if you don't use it? That should be zero-overhead. To answer the question, there is no other shared ownership pointer in the standard library; it doesn't provide every possible solution for every problem. – Jonathan Wakely Dec 03 '21 at 12:35