Skip to content

Instantly share code, notes, and snippets.

@hanji
Created December 21, 2011 05:41
Show Gist options
  • Save hanji/1504778 to your computer and use it in GitHub Desktop.
Save hanji/1504778 to your computer and use it in GitHub Desktop.
smart pointer deleter is broken
/**
* smart_pointer_deleter_is_broken.cpp
* (c) 2011 Ji Han
* the specification of std::unique_ptr/std::shared_ptr is broken--
* default constructed Deleter has no way to pass size_type n to Alloc::deallocate(T*, size_type)
*/
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
template<typename T, typename Alloc = std::allocator<T> >
class Fred
{
private:
static Alloc alloc_;
struct Deleter
{
void operator()(T* p)
{
alloc_.deallocate(p, 0 /* a malloc/free allocator ignores this. but we _should_ pass in the size (how's that possible?) */);
}
};
friend struct Deleter;
// unique_ptr will call a default constructed Deleter to deallocate memory.
// that's fine with operator delete [] (which doesn't need the size info).
// however, a user-defined allocator has member function deallocate(T* p, size_type n).
// the standard mandates that n shall match what was passed to allocate(size_type n).
// a default constructed Deleter has no way to know that (n is not part of the type info).
std::unique_ptr<T [], Deleter> ptr_;
std::size_t num_;
public:
explicit Fred(std::size_t n, T val = T(0))
: num_(n),
ptr_(alloc_.allocate(n))
{
std::fill_n(&ptr_[0], n, val);
}
Fred(const Fred& other)
: num_(other.num_),
ptr_(alloc_.allocate(other.num_))
{
std::copy_n(&other.ptr_[0], other.num_, &ptr_[0]);
}
Fred& swap(Fred& other)
{
if (this != &other)
{
std::swap(num_, other.num_);
ptr_.swap(other.ptr_);
}
return *this;
}
Fred& operator=(const Fred& other)
{
if (this != &other)
{
Fred tmp(other);
swap(tmp);
}
return *this;
}
~Fred() { }
const T& operator[](std::size_t i) const
{
return ptr_[i];
}
T& operator[](std::size_t i)
{
return ptr_[i];
}
std::string toString() const
{
std::ostringstream oss;
for (std::size_t i = 0; i < num_; ++i)
{
oss << (*this)[i];
}
return oss.str();
}
};
template<typename T, typename Alloc> Alloc Fred<T, Alloc>::alloc_ = Alloc();
int main()
{
Fred<int> a(3), b(5), c(7);
a[0]=0; a[1]=1; a[2]=2;
b[0]=5; b[1]=4; b[2]=3; b[3]=2; b[4]=1;
c[0]=1; c[1]=4; c[2]=2; c[3]=8; c[4]=5; c[5]=7;
std::cout << a.toString() << std::endl;
std::cout << b.toString() << std::endl;
std::cout << c.toString() << std::endl;
a.swap(b);
c = a;
std::cout << a.toString() << std::endl;
std::cout << b.toString() << std::endl;
std::cout << c.toString() << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment