第十六章 16.1.6节练习

练习16.28

编写你自己版本的shared_ptr和unique_ptr。

解答:

(2015年02月04日更新)

感谢 隔壁的程序员 指出之前实现中的问题(可见评论)。

(shared_ptr带删除器的析构函数部分略微复杂,参考了 http://stackoverflow.com/questions/9200664/how-is-the-stdtr1shared-ptr-implemented 中的提到实现)


#include 
#include 

template 
class shared_ptr{
	struct del_base{
		long int count;
		del_base(){}
		virtual void destroy() = 0;
		virtual ~del_base() {} //must be polymorphic
	};

	template
	struct deleter :del_base{
		D del;
		U *p;

		deleter(U *ptr, D d) :p(ptr), del(d){}
		virtual void destroy() { del(p); }
	};

public:
	shared_ptr() = default;
	shared_ptr(std::nullptr_t) : shared_ptr() {}
	template  explicit shared_ptr(U* p) : del_(nullptr), ptr(p), ref_num(new std::size_t(1)){}
	template  shared_ptr(U* p, D del) : del_(new deleter(p, del)), ptr(p), ref_num(new std::size_t(1)){}

	shared_ptr(const shared_ptr& ori) : ptr(ori.ptr), del_(ori.del_), ref_num(ori.ref_num){
		(*ref_num)++;
	}

	~shared_ptr(){
		if (*ref_num && --(*ref_num) == 0){
			del_ ? del_->destroy() : delete ptr;
			delete ref_num;
		}
	}

	shared_ptr& operator=(const shared_ptr& x) {
		(*ref_num)++;
		return *this;
	}

	operator bool() const {
		return !!ptr;
	}

	T& operator*() const {
		return *ptr;
	}

	T* operator->() const {
		return &this->operator*();
	}

	T* get() const {
		return ptr;
	}

	bool unique() const {
		return ((*ref_num) == 1);
	}

	long int use_count() const {
		return *ref_num;
	}

	del_base *del_;

private:
	T *ptr;
	std::size_t *ref_num = new std::size_t(0);
};


template>
class unique_ptr{
public:
	unique_ptr() = default;
	explicit unique_ptr(const T* p) :have_deleter(false), ptr(p){}
	unique_ptr(const T* p, D d) : have_deleter(true), ptr(p), deleter(d){}
	unique_ptr(std::nullptr_t) : have_deleter(false), unique_ptr(){}
	unique_ptr(const unique_ptr&) = delete;

	~unique_ptr(){
		deleter(ptr);

	}

	operator bool() const {
		return !!ptr;
	}

	T& operator*() const {
		return *ptr;
	}

	T* operator->() const {
		return &this->operator*();
	}

	T* get() const {
		return ptr;
	}

	T& operator[](std::size_t i) const{
		return ptr[i];

	}

	const D& get_deleter() const {
		return deleter;
	}

	T release() {
		T tmp = *ptr;
		~unique_ptr();
		return tmp;
	}

	void reset(void *q = nullptr) {
		auto tmp_p = static_cast(ptr);
		tmp_p = q;
	}

private:
	bool have_deleter;
	T *ptr;
	D deleter;
};

int main(){
	// 测试例子,这里主要为了测试析构函数。因为函数模板只有一个模板参数,这里实现起来有些困难。
	// 感觉其他部分简单的测试了下,感觉没有问题,就不将测试例放上来了。
	/**
	带删除器的例子
	参考 http://www.cplusplus.com/reference/memory/shared_ptr/~shared_ptr/
	*/
	{
		auto deleter = [](int*p){
			std::cout << "[deleter called]\n\n"; delete p;
		};

		shared_ptr foo(new int, deleter);
		//std::shared_ptr foo(new int, deleter);//可以用标准库中的std::shared_ptr和自己实现的进行对比

		std::cout << "test case 1:\nuse_count: " << foo.use_count() << '\n';
	}
	/**
	简单使用方式的例子
	更多简单方式可参考 http://www.cplusplus.com/reference/memory/shared_ptr/shared_ptr/
	*/
	std::shared_ptr p1;
	std::shared_ptr p2(nullptr);
	std::shared_ptr p3(new int);
	std::shared_ptr p4(new int, std::default_delete());
	std::shared_ptr p5(p4);

	shared_ptr my_p1;
	shared_ptr my_p2(nullptr);
	shared_ptr my_p3(new int);
	shared_ptr my_p4(new int, std::default_delete());
	shared_ptr my_p5(my_p4);

	std::cout << "test case 2:\nuse_count:\n";
	std::cout << "p1: (std)" << p1.use_count() << " vs. (my)" << my_p1.use_count() << '\n';
	std::cout << "p2: (std)" << p2.use_count() << " vs. (my)" << my_p2.use_count() << '\n';
	std::cout << "p3: (std)" << p3.use_count() << " vs. (my)" << my_p3.use_count() << '\n';
	std::cout << "p4: (std)" << p4.use_count() << " vs. (my)" << my_p4.use_count() << '\n';
	std::cout << "p5: (std)" << p5.use_count() << " vs. (my)" << my_p5.use_count() << '\n' << std::endl;;

	return 0;
}


测试例的输出如下:

test case 1:
use_count: 1
[deleter called]

test case 2:
use_count:
p1: (std)0 vs. (my)0
p2: (std)0 vs. (my)0
p3: (std)1 vs. (my)1
p4: (std)2 vs. (my)2
p5: (std)2 vs. (my)2

只是实现了部分,有些可能需要使用移动操作才能实现。

对于移动操作的理解还不是很深,所以没有用移动的方式来实现类中的函数。


练习16.29

修改你的Blob类,用你自己的shared_ptr代替标准库中的版本。

解答:

如果行为都是一样的,那么就没有什么区别。

这里可能更多的是去验证类实现的正确性。


练习16.30


练习16.31

如果我们将DebugDelete与unique_ptr一起使用,解释编译器将删除器处理未内联形式的可能方式。

解答:

non-specialized
template > class unique_ptr;
array specialization
template  class unique_ptr;
这里应该会通过绑定删除器的类型,然后用删除器的函数运算符来执行删除过程,就向像我16.28题中写的那样。(这是我个人的理解,没有找到太好的参考资料)


你可能感兴趣的:(C++,primer,5ed)