谈谈observer_ptr | Blurred code

谈谈observer_ptr

panda

2019/05/25

LastMod:2021/02/23

Categories: cpp STL

observer_ptr是于14年的提案N42821提出的一种“世界上最蠢的智能指针",现在的observer_ptrstd::experimental::memory里,当然也可以自己写一个,observer_ptr的代码简单到”代码即文档“的级别了,但是目前来看observer_ptr应该是进不了标准库了,因为Bjarne Stroustrup在提案P1408R02:里有力的驳斥了observer_ptr

What is observer_ptr

和智能指针家族的其他兄弟们一样(weak_ptr,shared_ptr,unique_ptr),observer_ptr也是为了处理资源管理问题而诞生的。C++在语言层面上没有提供一种只读指针,当我们需要用指针来指代某个数据而使用raw_pointer,也即T*时,我们需要时刻紧绷心弦,一旦对本意为只读的指针错误的使用了delete,就会造成意料之外的资源释放。

一种可行的方案是采用自定义删除器的unique_ptr,如

template <typename T>
	using read_only_ptr = unique_ptr<T,[](){/*do nothing*/};

这样通过取消unique_ptr的删除操作,可以避免被观察的对象被意外释放。然而unique_ptr的拷贝操作是被禁用的,一个用于只读某个对象的指针却不能被拷贝,这很让人迷惑。所以改进后的observer_ptr应该是这样:

tempate <typename T>
	class observer_ptr
	{
		private:
			T* ptr;
		public:
		observer_ptr(T* pt):ptr(pt){}
		~observer_ptr(){/*do nothing*/}
		T* get(){return ptr;}
		//other codes to work with STL......
	}

observer_ptr应该可以正确访问所指代的对象,表现的类似T*,拥有dereference->操作,它析构的时候应该无任何副作用,不对指针指向的区域造成任何影响。

Problems

observer_ptr看起来解决了一个关于只读指针的痛点,为C++彻底删除原始指针的宏大目标又前进了一步,然而比起observer_ptr所解决的问题,它带来了更多的麻烦。

Bjarne还指出,T*在代码中非常常用。如果都要替换成observer_ptr,模板展开的时间会拖慢编译速度。 Bjarne提出的替代方案是

	template <typename T>
		using observer_ptr = T*;

通过模板别名来表示非拥有指针,而拥有资源的指针一律使用unique_ptrshared_ptr,但是不从代码上对delete进行禁用。错误使用应该由错误的程序员负责,这很cpp。


  1. A Proposal for the World's Dumbest Smart Pointer, v4 ↩︎

  2. Abandon observer_ptr ↩︎