std::shared_ptr has specializations for atomic operations like atomic_compare_exchange_weak and family, but I cannot find documentation on equivalent specializations for std::unique_ptr. Are there any? If not, why not?
The reason that it is possible to provide an atomic instance of std::shared_ptr and it is not possible to do so for std::unique_ptr is hinted at in their signature. Compare:
std::shared_ptr<T> vs
std::unique_ptr<T, D> where D is the type of the Deleter.
std::shared_ptr needs to allocate a control-block where the strong and weak count are kept, so type-erasure of the deleter came at a trivial cost (a simply slightly larger control-block).
As a result, the layout of std::shared_ptr<T> is generally similar to:
template <typename T>
struct shared_ptr {
T* _M_ptr;
SomeCounterClass<T>* _M_counters;
};
And it is possible to atomically perform the exchange of those two pointers.
std::unique_ptr has a zero-overhead policy; using a std::unique_ptr should not incur any overhead compared to using a raw pointer.
As a result, the layout of std::unique_ptr<T, D> is generally similar to:
template <typename T, typename D = default_delete<T>>
struct unique_ptr {
tuple<T*, D> _M_t;
};
Where the tuple uses EBO (Empty Base Optimization) so that whenever D is zero-sized then sizeof(unique_ptr<T>) == sizeof(T*).
However, in the cases where D is NOT zero-sized, the implementation boils down to:
template <typename T, typename D = default_delete<T>>
struct unique_ptr {
T* _M_ptr;
D _M_del;
};
This D is the kicker here; it is not possible, in general, to guarantee that D can be exchange in an atomic fashion without relying on mutexes.
Therefore, it is not possible to provide an std::atomic_compare_exchange* suite of specialized routine for the generic std::unique_ptr<T, D>.
Note that the standard does not even guarantee that sizeof(unique_ptr<T>) == sizeof(T*) AFAIK, though it's a common optimization.
No there no standard atomic functions for std::unique_ptr.
I did find an argument for why not in Atomic Smart Pointers(N4058) by Herb Sutter
Lawrence Crowl responded to add:
One of the reasons that shared_ptr locking is the way it is is to avoid a situation in which we weaken the precondition on the atomic template parameter that it be trivial, and hence have no risk of deadlock.
That said, we could weaken the requirement so that the argument type only needs to be lockfree, or perhaps only non-recursively locking.
However, while trivial makes for reasonably testable traits, I see no effective mechanism to test for the weaker property.
That proposal has been assigned to the Concurrency Subgroup and has no disposition as of yet. You can check the status at JTC1/SC22/WG21 - Papers 2014 mailing2014-07
Be careful, sharing a modifiable unique_ptr between threads rarely makes sense, even if the pointer itself was atomic. If its contents changes, how can other threads know about it? They can't.
Consider this example:
unique_ptr<MyObject> p(new MyObject);
// Thread A
auto ptr = p.get();
if (ptr) {
ptr->do_something();
}
// Thread B
p.reset();
How can Thread A avoid using a dangling pointer after calling p.get()?
If you want to share an object between threads, use shared_ptr which has reference counting exactly for this purpose.
If you really wanted it, you can always roll your own atomic_unique_ptr, something along the lines (simplified):
#pragma once
#include <atomic>
#include <memory>
template<class T>
class atomic_unique_ptr
{
using pointer = T *;
std::atomic<pointer> ptr;
public:
constexpr atomic_unique_ptr() noexcept : ptr() {}
explicit atomic_unique_ptr(pointer p) noexcept : ptr(p) {}
atomic_unique_ptr(atomic_unique_ptr&& p) noexcept : ptr(p.release()) {}
atomic_unique_ptr& operator=(atomic_unique_ptr&& p) noexcept { reset(p.release()); return *this; }
atomic_unique_ptr(std::unique_ptr<T>&& p) noexcept : ptr(p.release()) {}
atomic_unique_ptr& operator=(std::unique_ptr<T>&& p) noexcept { reset(p.release()); return *this; }
void reset(pointer p = pointer()) { auto old = ptr.exchange(p); if (old) delete old; }
operator pointer() const { return ptr; }
pointer operator->() const { return ptr; }
pointer get() const { return ptr; }
explicit operator bool() const { return ptr != pointer(); }
pointer release() { return ptr.exchange(pointer()); }
~atomic_unique_ptr() { reset(); }
};
template<class T>
class atomic_unique_ptr<T[]> // for array types
{
using pointer = T *;
std::atomic<pointer> ptr;
public:
constexpr atomic_unique_ptr() noexcept : ptr() {}
explicit atomic_unique_ptr(pointer p) noexcept : ptr(p) {}
atomic_unique_ptr(atomic_unique_ptr&& p) noexcept : ptr(p.release()) {}
atomic_unique_ptr& operator=(atomic_unique_ptr&& p) noexcept { reset(p.release()); return *this; }
atomic_unique_ptr(std::unique_ptr<T>&& p) noexcept : ptr(p.release()) {}
atomic_unique_ptr& operator=(std::unique_ptr<T>&& p) noexcept { reset(p.release()); return *this; }
void reset(pointer p = pointer()) { auto old = ptr.exchange(p); if (old) delete[] old; }
operator pointer() const { return ptr; }
pointer operator->() const { return ptr; }
pointer get() const { return ptr; }
explicit operator bool() const { return ptr != pointer(); }
pointer release() { return ptr.exchange(pointer()); }
~atomic_unique_ptr() { reset(); }
};
NB: The code provided in this post is hereby released into Public Domain.
Related
I'm trying to create a not-null unique_ptr.
template <typename T>
class unique_ref {
public:
template <class... Types>
unique_ref(Types&&... Args) { mPtr = std::make_unique<T, Types...>(std::forward<Types>(Args)...); }
T* release() && { return mPtr.release(); }
T* release() & = delete;
private:
std::unique_ptr<T> mPtr;
};
My goal is to allow release() only if the unique_ref is a temporary.
The problem is someone could use std::move() to "get around" this:
unique_ref<int> p;
int* p2 = std::move(p).release();
Is there a way to prevent it from being move'd?
There is no way of distinguishing prvalues (temporaries) from xvalues (result of std::move) as far as overload resolution is concerned.
And there is no way of preventing std::move from converting an lvalue to an xvalue.
release is not an operation that can be supported by a non-null-guarantee "unique pointer". And neither is move construction / assignment. As far as I can tell, the only way to make the guarantee is to make the pointer non-movable, and make the copy operation allocate a deep copy.
You're going to have to let the std::move case go. When a user invokes std::move, they are giving a strong signal that they know exactly what they are doing.
You can protect yourself though during debug time.
For example, I would consider starting the class definition a little like this:
#include <memory>
#include <cassert>
template <typename T>
class unique_ref {
public:
// a number of problems here, but that is a discussuion for another day
template <class... Types>
unique_ref(Types&&... Args)
: mPtr(std::make_unique<T>(std::forward<Types>(Args)...))
{ }
// unique_ref is implicitly move-only
// see check below
bool has_value() const {
return bool(mPtr);
}
// here I am implicitly propagating the container's constness to the
// inner reference yielded. You may not want to do that.
// note that all these accessors are marshalled through one static function
// template. This gives me control of behaviour in exactly one place.
// (DRY principles)
auto operator*() -> decltype(auto) {
return *get_ptr(this);
}
auto operator*() const -> decltype(auto) {
return *get_ptr(this);
}
auto operator->() -> decltype(auto) {
return get_ptr(this);
}
auto operator->() const -> decltype(auto) {
return get_ptr(this);
}
private:
using implementation_type = std::unique_ptr<T>;
implementation_type release() { return std::move(mPtr); }
// this function is deducing constness of the container and propagating it
// that may not be what you want.
template<class MaybeConst>
static auto get_ptr(MaybeConst* self) -> decltype(auto)
{
auto ptr = self->mPtr.get();
assert(ptr);
using self_type = std::remove_pointer_t<decltype(self)>;
if constexpr (std::is_const<self_type>())
return static_cast<T const*>(ptr);
else
return ptr;
}
private:
implementation_type mPtr;
};
struct foo
{
};
auto generate()->unique_ref<foo> {
return unique_ref<foo>();
}
void test()
{
auto rfoo1 = generate();
auto rfoo2 = generate();
// auto rfoo3 = rfoo1; not copyable
// we have to assume that a user knows what he's doing here
auto rfoo3 = std::move(rfoo1);
// but we can add a check
assert(!rfoo1.has_value());
auto& a = *rfoo3;
static_assert(!std::is_const<std::remove_reference_t<decltype(a)>>());
const auto rfoo4 = std::move(rfoo3);
auto& b = *rfoo4;
static_assert(std::is_const<std::remove_reference_t<decltype(b)>>());
}
I am currently integrating a datastore library into my application. I need to be able to mock this datastore (which is I/O intensive) for my unit tests, therefore creating a wrapper around that library's interface.
Unfortunately, in its interface, this library returns iterators as pointers and not as values, because they are polymorphic at runtime.
My issue is that because of the layer of polymorphism I am adding, it seems unavoidable to add iterators that are polymorphic at runtime, therefore incurring a new level of indirection and some more dynamic allocation...
// Library code
class LibIterator
{
// pure virtual methods
};
class LibDataStore
{
LibIterator* getIt();
};
// My interface
class IMyIterator{
// pure virtual methods
};
class MyLibIterator : public IMyIterator
{
std::unique_ptr<LibIterator> m_iterator;
};
class MyIterator
{
std::unique_ptr<MyLibIterator> m_iterator;
};
class IMyDataStore
{
MyIterator getIt();
};
That is an awful lot of pointers to dereference, of virtual dispatch on each use of any method of the iterator, plus at least 2 dynamic allocations (the lib iterator + mine) for each iterator creation...
I was thinking of using CRTP to help with this, but I can't figure out a way to prevent code using IMyDataStore to see the concrete implementation of the iterator bleeding through MyIterator's type.
Is there any trick I might have missed?
template<class T, std::size_t sz, std::size_t algn>
struct poly {
if you are not afraid yet you should be
poly_vtable<T> const* vtable=0;
std::aligned_storage_t<sz, algn> data;
we can cover the vtable later.
T* get() { return vtable->get(&data); }
T const* get() const { return vtable->get((void*)&data); }
example use of vtable. Here is setup:
template<class U, class...Args>
U* emplace(Args&&...args){
static_assert(sizeof(U)<=sz && alignof(U)<=algn, "type too large");
clear();
U* r = ::new((void*)&data) U(std::forward<Args>(args)...);
vtable = get_poly_vtable<T,U>();
return r;
}
copy:
poly(poly const& o){
if (!o.vtable) return;
o.vtable->copy( &data, &o.data );
vtable=o.vtable;
}
poly(poly&& o){
if (!o.vtable) return;
o.vtable->move( &data, &o.data );
vtable=o.vtable;
}
poly& operator=(poly const& rhs) {
if (this == &rhs) return *this;
clear();
if (!rhs.vtable) return *this;
rhs.vtable->copy( &data, &rhs.data );
vtable = rhs.vtable;
return *this;
}
poly& operator=(poly&& rhs) {
if (this == &rhs) return *this;
clear();
if (!rhs.vtable) return *this;
rhs.vtable->move( &data, &rhs.data );
vtable = rhs.vtable;
return *this;
}
destruction:
void clear(){
if (!vtable) return;
vtable->dtor(&data);
vtable=nullptr;
}
~poly(){clear();}
pointer like operations:
explicit operator bool()const{return vtable;}
T& operator*(){ return *get();}
T const& operator*() const{ return *get();}
T* operator->(){ return get();}
T const* operator->() const{ return get();}
construct from a type derived from T:
template<class U,
class dU=std::decay_t<U>,
class=std::enable_if_t<!std::is_same<dU, poly>{}>,
class=std::enable_if_t<std::is_base_of<T, dU>{}>
>
poly(U&& u) {
emplace<std::decay_t<U>>( std::forward<U>(u) );
}
};
note that this type when const refers to a const value.
The idea is that poly<T> is a polymorphic value of type T. It has size limits.
You can use the T* vtable to arrange for polymorphism of other operations.
template<class T>
struct poly_vtable{
T*(*get)(void*)=0;
void(*copy)(void*,void const*)=0;
void(*move)(void*,void*)=0;
void(*dtor)(void*)=0;
};
template<class T, class U>
poly_vtable<T> make_poly_vtable() {
return {
[](void* ptr)->T*{ return static_cast<U*>(ptr); },
[](void* dest, void const* src){ ::new(dest) U(*static_cast<U const*>(src)); },
[](void* dest, void* src){ ::new(dest) U(std::move(*static_cast<U*>(src))); },
[](void* ptr){ static_cast<U*>(ptr)->~U(); }
};
}
template<class T, class U>
poly_vtable<T> const* get_poly_vtable() {
static const auto r = make_poly_vtable<T,U>();
return &r;
}
get_poly_vtable<T,U>() returns a pointer to a static local poly_vtable<T> with each operation implemented.
Live example.
Now you can have a vtable based polymorphic value type.
The same technique can be extended to more operations; simply cast-to-base and using real vtables is easier.
Using this, you store a poly<IMyIterator, 64, alignof(IMyIterator)>. This is a value type containing some buffer of 64 bytes.
Another approach to reduce indirection would be to replace the concept of per-item visitation with possibly repeated range visitation.
If you visit a range of 10 items at once per callback, then the overhead of invoking virtual methods is up to 10 times less than one per callback.
You can create input iterators with a range object that has a buffer for up to 10 items in it and who automatically rebuild it when you reach the end, if there are more available, getting the data in batches.
I store "instances of different types" with "shared ownership". That's what I currently do:
class Destructible {
public:
virtual ~Destructible() = default;
};
// UGLY
class MyType1 : public Destructible { ... };
class MyTypeN : public Destructible { ... };
class Storage {
std::vector<std::shared_ptr<Destructible>> objects_;
...
}
I'd love to switch to boost::any, removing all these conformances and gaining the ability to store instances of truly any type. Also I like boost::any interface and boost::any_cast.
But my types don't satisfy ValueType requirements, they are not copyable. What is the best (preferably existing) solution for this problem? Something like shared_any_ptr, which captures destructor at creation, has type erasure, reference counter and can do any_cast.
Edit: boost::any allows creation with move, but I'd prefer not to even move and use pointers.
Edit2: I also use make_shared extensively, so something make_shared_any_ptr would come in handy.
This isn't tricky with shared pointers. We can even avoid multiple allocations.
struct any_block {
any_block(any_block const&)=delete;
template<class T>
T* try_get() {
if (!info || !ptr) return nullptr;
if (std::type_index(typeid(T)) != std::type_index(*info)) return nullptr;
return static_cast<T*>(ptr);
}
template<class T>
T const* try_get() const {
if (!info || !ptr) return nullptr;
if (std::type_index(typeid(T)) != std::type_index(*info)) return nullptr;
return static_cast<T const*>(ptr);
}
~any_block() {
cleanup();
}
protected:
void cleanup(){
if (dtor) dtor(this);
dtor=0;
}
any_block() {}
std::type_info const* info = nullptr;
void* ptr = nullptr;
void(*dtor)(any_block*) = nullptr;
};
template<class T>
struct any_block_made:any_block {
std::aligned_storage_t<sizeof(T), alignof(T)> data;
any_block_made() {}
~any_block_made() {}
T* get_unsafe() {
return static_cast<T*>((void*)&data);
}
template<class...Args>
void emplace(Args&&...args) {
ptr = ::new((void*)get_unsafe()) T(std::forward<Args>(args)...);
info = &typeid(T);
dtor = [](any_block* self){
static_cast<any_block_made<T>*>(self)->get_unsafe()->~T();
};
}
};
template<class D>
struct any_block_dtor:any_block {
std::aligned_storage_t<sizeof(D), alignof(D)> dtor_data;
any_block_dtor() {}
~any_block_dtor() {
cleanup();
if (info) dtor_unsafe()->~D();
}
D* dtor_unsafe() {
return static_cast<D*>((void*)&dtor_data);
}
template<class T, class D0>
void init(T* t, D0&& d) {
::new( (void*)dtor_unsafe() ) D(std::forward<D0>(d));
info = &typeid(T);
ptr = t;
dtor = [](any_block* s) {
auto* self = static_cast<any_block_dtor<D>*>(s);
(*self->dtor_unsafe())( static_cast<T*>(self->ptr) );
};
}
};
using any_ptr = std::shared_ptr<any_block>;
template<class T, class...Args>
any_ptr
make_any_ptr(Args&&...args) {
auto r = std::make_shared<any_block_made<T>>();
if (!r) return nullptr;
r->emplace(std::forward<Args>(args)...);
return r;
}
template<class T, class D=std::default_delete<T>>
any_ptr wrap_any_ptr( T* t, D&& d = {} ) {
auto r = std::make_shared<any_block_dtor<std::decay_t<D>>>();
if (!r) return nullptr;
r->init( t, std::forward<D>(d) );
return r;
}
you'd have to implement any_cast, but with try_get<T> it should be easy.
There may be some corner cases like const T that the above doesn't handle.
template<class T>
std::shared_ptr<T>
crystalize_any_ptr( any_ptr ptr ) {
if (!ptr) return nullptr;
T* pt = ptr->try_get<T>();
if (!pt) return nullptr;
return {pt, ptr}; // aliasing constructor
}
This lets you take a any_ptr and turn it into a shared_ptr<T> if the types match without copying anything.
live example.
You'll notice how similar any_block_made and any_block_dtor is. I believe that this is why at least one major shared_ptr in a std library reuses the spot the deleter lives in for make_shared itself.
I could probably do similar, and reduce binary size here. In addition, the T/D parameter of any_block_made and any_block_dtor is really just about how big and aligned the block of memory we play with is, and what exactly type erasued helper I store in the dtor pointer in the parent. A compiler/linker with COMDAT folding (MSVC or GOLD) may eliminate the binary bloat here, but with a bit of care I could do it myself.
I'm currently working on some code using smart pointers in which it is necessary at a number of points to cast these pointers to their base types and pass them as const arguments to functions. Currently I'm using shared_ptr's and the standard pointer casting functions to achieve this, but this seems inefficient (as each cast costs at least one CAS) and also misleading (as we are not modelling a shared relationship, the parent is the sole owner of the object).
I therefore came up with the following but wanted to check it is indeed safe, or is there some edge case which will break it?
template <typename ToType, typename FromType>
class FTScopedCastWrapper {
public:
explicit FTScopedCastWrapper(std::unique_ptr<FromType>& p) : from_ptr_(&p) {
auto d = static_cast<ToType *>(p.release());
to_ptr_ = std::unique_ptr<ToType>(d);
}
~FTScopedCastWrapper() {
auto d = static_cast<FromType *>(to_ptr_.release());
(*from_ptr_) = std::unique_ptr<FromType>(d);
}
const std::unique_ptr<ToType>& operator()() {
return to_ptr_;
}
// Prevent allocation on the heap
void* operator new(size_t) = delete;
void* operator new(size_t, void*) = delete;
void* operator new[](size_t) = delete;
void* operator new[](size_t, void*) = delete;
private:
std::unique_ptr<FromType>* from_ptr_;
std::unique_ptr<ToType> to_ptr_;
};
template <typename ToType, typename FromType>
FTScopedCastWrapper<ToType, FromType> FTScopedCast(std::unique_ptr<FromType>& p) {
return FTScopedCastWrapper<ToType, FromType>(p);
}
The intended usage is then
void testMethod(const std::unique_ptr<Base>& ptr) {
// Do Stuff
}
auto ptr = std::make_unique<Derived>();
testMethod(FTScopedCast<Base>(ptr)());
The deleter is not carried across as doing so would prevent upcasting. It also doesn't make sense to do so as the deleter will never be invoked on the created smart pointer anyway.
Allocation on the heap is prevented as it could allow the wrapper to outlive the pointer it wraps, copying is prevented by the std::unique_ptr member and standard destruction order will ensure the raw pointer is returned to the original smart pointer before it is destroyed, even if it is declared in the same scope as the wrapper.
I'm aware this is not thread safe but I'd argue sharing a unique_ptr between threads is breaking its contract of a single owner.
If I understand you correctly, the intention is to "steal" the contents of a std::unique_ptr for the duration of the function call, and then return it to its original owner when the function call is complete.
But this just seems needlessly convoluted. For a start, as pointed out by #TheUndeadFish in the comments, you could just take a raw Base* as the function argument and call it with std::unique_ptr::get(). As long as the called function doesn't do something silly like call delete on the passed-in pointer or squirrel it away in a static variable for later use then this will work just fine.
Alternatively, if you find raw pointers completely distasteful, you could use a non-owning pointer wrapper, something like the following (untested, but you get the idea):
template <typename T>
class unowned_ptr {
public:
unowned_ptr() = default;
unowned_ptr(const unowned_ptr&) = default;
unowned_ptr& operator=(const unowned_ptr&) = default;
template <typename U>
unowned_ptr(const U* other) : ptr(other) {}
template <typename U>
unowned_ptr(const std::unique_ptr<U>& other) : ptr(other.get()) {}
T* operator->() { return ptr; }
const T* operator->() const { return ptr; }
private:
T* ptr = nullptr;
};
Something very similar to this, std::observer_ptr ("the world's dumbest smart pointer") was proposed for C++17, but I'm not sure of the status.
I am a bit embarrassed of asking such a simple question:
Is there any pointer class in cpp that initializes itself with nullptr but is 100% compatible to a basic c-stylish pointer?
to write:
extern "C" void someFunction(const Struct* i_s);
std::ptr<Struct> p;
// ...
p = new Struct;
// ...
someFunction(p);
Is there such a thing?
Or maybe in boost or Qt?
Edit: to make it clear: iam not searching for a smart pointer that takes ownership of the pointer and does ref counting.
You can use the following syntax
std::unique_ptr<Struct> up{};
(or std::shared_ptr). This way, the pointer is value-initialized, i.e. nullptr is being assigned to it.
See http://en.cppreference.com/w/cpp/memory/unique_ptr/unique_ptr for details about the default constructor.
If you looking for a "smart" pointer that just initialized by default with nullptr, then you can write a wrapper. A very basic version below:
#include <iostream>
template <typename T>
struct safe_ptr
{
T* _ptr;
explicit safe_ptr(T* ptr = nullptr):_ptr{ptr}{}
operator T*() const {return _ptr;}
safe_ptr& operator=(T* rhs)
{
_ptr = rhs;
return *this;
}
};
void test(int* p){}
int main()
{
safe_ptr<int> s;
if(s==nullptr)
std::cout << "Yes, we are safe!" << std::endl;
// test that it "decays"
test(s);
s = new int[10]; // can assign
delete[] s; // can delete
}
There is no such thing in C++ since all of the special pointer classes implement some form of ownership other than "maintained by someone else". You could technically use shared_ptr with an empty deleter but that adds reference counting you don't actually need.
The correct C++ solution is to just always add = 0; or = nullptr; to your raw pointer declarations that aren't initialized at declaration.
All that said, this question is tagged just as C++ so the idiomatic answer is to not use raw pointers in your code (except for non-owning cases obviously).
100% compatible to a basic c-stylish pointer
std::unique_ptr and std::shared_ptr do not have automatic conversions to a raw pointer, and that's a good thing as it would inevitably lead to horrible bugs. They take ownership, and in your comments you explicitly say:
the pointer should not take ownership of the given Pointer.
If you insist, you can define a "smart" pointer class yourself:
template <class T>
class RawPointer final
{
private:
T* raw_ptr;
public:
RawPointer(T* raw_tr) : raw_ptr(raw_ptr) {}
RawPointer() : raw_ptr(nullptr) {}
operator T*() const { return raw_ptr; }
};
struct Struct
{
};
void someFunction(const Struct* i_s);
int main()
{
RawPointer<Struct> p;
someFunction(p);
}
Is this a good idea? Probably not. You should just get into the habit of initializing your raw pointers:
Struct* p = nullptr;
On the other hand, people are thinking about a very similar addition to the standard library in the future. You may find A Proposal for the World’s Dumbest Smart Pointer an interesting read.
If this is really the behavior that you want, it would be trivial to implement it yourself in a template. Here's one such implementation:
template<class T>
class ptr_t{
T* ptr;
public:
ptr_t() : ptr(nullptr){ }
ptr_t(const ptr_t& other) : ptr(other.ptr){ }
ptr_t(T* other) : ptr(other){ }
T& operator*(){
return *ptr;
}
T* operator->(){
return ptr;
}
template<class U>
operator U(){
return (U)ptr;
}
}
However, the amount of convenience you will gain from such a device will be rather limited. You're probably much better off taking another approach.