Reputation: 1995
While both shared pointers and unique pointers in C++11 allow user defined deleters, they have notable syntax differences, as shown in the below mini example:
#include "pch.h"
#include <memory>
class factory
{
public:
static factory * create() {
return new factory();
}
static void destroy(factory* fp) noexcept{
delete fp;
}
factory(const factory &) = delete;
factory& operator= (const factory &) = delete;
private:
char * p_;
factory() {
p_ = new char[100];
}
~factory() {
delete[] p_;
}
};
int main()
{
typedef void(*fp)(factory*);
auto del = [](factory * p) noexcept {
factory::destroy(p);
};
std::shared_ptr<factory> fsptr1(factory::create(), del);
std::shared_ptr<factory> fsptr2(factory::create(), del);
//notice the syntax is different
std::unique_ptr<factory, fp> ufsptr1(factory::create(), del);
std::unique_ptr<factory, decltype(del)> ufsptr2(factory::create(), del);
return 0;
}
The reason behind this is that the template class for shared pointers is defined as
template< class T > class shared_ptr;
and the template class for unique pointers is defined as
template<class T, class Deleter = std::default_delete<T>> class unique_ptr;
My question is: Is there any reason behind this design decision that the syntax of the two differentiates itself from each other? My naive thinking is that if the template class for shared pointers is made as
template< class T, class Deleter = std::default_delete<T>> class shared_ptr;
it will makes more sense. For one thing, it is consistent with the case of unique pointers, and for another, it won't instantiate when the default deleter is not well formed and the user fails to provide a custom one.
Upvotes: 2
Views: 90
Reputation: 22023
The default std::unique_ptr
is only storing one element, the pointer to the data it protects. This is because by default, you want to use the least amount of memory possible. But when you specify a deleter, you need also to store it. So you need to differentiate between the two versions.
See here: https://github.com/llvm-mirror/libcxx/blob/master/include/memory#L2397
The storage is a specific type based on the template types.
But for std::shared_ptr
, you don't have this constraint, you already have a counter, you need to allocate a block to store it. So you can make the deletion choice inside the allocation logic instead of outside, at the API level.
See here: https://github.com/llvm-mirror/libcxx/blob/master/include/memory#L3592
The compressed_pair
is not in the smart pointer itself, but in the allocated block.
Upvotes: 5