What's the most convenient way to be able to store either std::shared_ptr or Foo* in the same type?
Foo* a = ...;
std::shared_ptr<Foo> b = ...;
Bar c = a; // Success, Bar type can hold Foo*
Bar d = b; // Success, Bar type can also hold std::shared_ptr<Foo>
std::variant<Foo*, std::shared_ptr< Foo>> is okay, but it's not possible to dereference it directly and that is kind of annoying. Is there a better way?
The difference is that std::make_shared performs one heap-allocation, whereas calling the std::shared_ptr constructor performs two.
The shared_ptr type is a smart pointer in the C++ standard library that is designed for scenarios in which more than one owner might have to manage the lifetime of the object in memory.
Here is an example of how we create a shared_ptr that is empty but still pointing to an object: int x = 100; //'px' holds &x, but is empty. //A null and empty shared_ptr<void> is passed //to aliasing constructor to initialize px std::shared_ptr<int> px(std::shared_ptr<void>(), &x);
std::make_sharedConstructs an object of type T and wraps it in a std::shared_ptr using args as the parameter list for the constructor of T .
(since C++11) std::shared_ptr is a smart pointer that retains shared ownership of an object through a pointer. Several shared_ptr objects may own the same object. The object is destroyed and its memory deallocated when either of the following happens:
Having an std::shared_ptr as the user-data pointer, as opposed to a raw pointer, is safer because it makes it easier to manage the lifecycle of the associated user-data or context. One way to use std::shared_ptr for user-data is to define an interface that clients can inherit.
Generally, it is said that the deleter of an std::shared_ptr is type-erased. To achieve this type-erasure, the std::shared_ptr stores the deleter as part of its control block.
The destructor of shared_ptr decrements the number of shared owners of the control block. If that counter reaches zero, the control block calls the destructor of the managed object. The control block does not deallocate itself until the std::weak_ptr counter reaches zero as well.
Just use a std::shared_ptr<Foo>
.
While it is rarely useful, you can in fact construct a non-owning non-counting std::shared_ptr
:
auto p = std::shared_ptr<Foo>{std::shared_ptr<void>(), raw_pointer};
If you want to cater to weird people disrespecting the abstraction (looking at the reference-counts, to be specific), you could also stash an eternal anchor somewhere and use that:
struct pass_t {
template <class... T>
constexpr int operator()(T&&...) noexcept
{ return 0; }
};
constexpr inline pass_t pass;
inline const std::shared_ptr<void> anchor {nullptr, pass};
auto p = std::shared_ptr<Foo>{anchor, raw_pointer};
Basically the same as Caleth's, but more generic and exposing the variant nature of that new type:
template <class... PointerTypes>
struct PointerHolder : std::variant<PointerTypes...> {
using std::variant<PointerTypes...>::variant;
auto *operator -> () const {
return &operator*();
}
auto &operator * () const {
return std::visit([](auto const &p) -> auto & { return *p; }, *this);
}
};
See it live on Wandbox
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With