其他分享
首页 > 其他分享> > c – 一个新的通用指针any_ptr(现在为dumb_ptr),使代码在智能指针中更具可重用性

c – 一个新的通用指针any_ptr(现在为dumb_ptr),使代码在智能指针中更具可重用性

作者:互联网

我最近一直在使用很多不同的boost智能指针,以及普通的指针.我注意到,随着您的开发,您倾向于意识到您必须切换指针类型和内存管理机制,因为您忽略了一些循环依赖或某些小烦人的事情.当发生这种情况并且你改变你的指针类型时,你必须去改变一大堆你的方法签名来采用新的指针类型,或者在每个调用站点你必须在指针类型之间进行转换.如果您具有相同的功能但希望它采用多种指针类型,则也会出现问题.

我想知道是否已经存在一种通用的处理方式,即写入与传递给它的指针类型无关的方法?

显然我可以看到几种方法来做到这一点,一种是为每种指针类型编写重载方法,但这很快就变得很麻烦.另一种是使用带有某种类型推断的模板样式解决方案,但这会在编译的代码中引起一些明显的膨胀,并且很可能开始抛出奇怪的无法解决的模板错误.

我的想法是编写一个新类any_ptr< T>来自所有主要指针类型的转换构造函数,例如,T *,shared_ptr< T>,auto_ptr< T>,scoped_ptr< T>也许甚至是weak_ptr< T>然后让它暴露*和 – >操作符.通过这种方式,它可以用于任何不将指针返回到函数外部的函数,并且可以使用公共指针类型的任意组合来调用.

我的问题是,这是一个非常愚蠢的事情吗?我发现它可能会被滥用,但假设它从未用于返回any_ptr的函数,那么我会遇到一个主要问题吗?请你的想法.

编辑1

阅读完答案之后,我想做一些评论太长的笔记.

首先是关于使用原始指针或引用(@shoosh).我同意你可以使函数使用原始指针,但后来假设我使用shared_ptr的情况,这意味着我必须在每个调用站点去ptr.get(),现在假设我意识到我做了一个循环引用,我必须将指针更改为weak_ptr然后我必须将所有这些调用站点更改为x.lock().get().现在我同意这不是灾难,但它很刺激,我觉得有一个优雅的解决方案.通过T& T也是如此.引用和转移* x,必须进行类似的呼叫站点更改.

我在这里尝试做的是使代码更优雅,即使通过指针类型的大变化也更容易重构.

其次关于smart_ptr语义:我同意由于不同的原因使用不同的智能指针,并且在复制和存储方面必须注意某些考虑因素(这就是为什么boost :: shared_ptr< T>不能自动转换的原因)到T *).

但是我设想any_ptr(回想起来可能是一个坏名字)只能用于不存储指针的情况(除了堆栈上的临时变量之外).它应该只是从各种智能指针类型隐式构造,重载*和 – >运算符并可转换为T *(通过自定义转换函数T *()).这样,any_ptr的语义与T *完全相同.因此,它应该仅用于可以安全使用原始ptr的地方(这是@Alexrere_C在评论中所说的).这也意味着@Matthieu_M所谓的“重型机械”都不会出现.

第三,关于模板.虽然模板对于某些人来说很棒,但由于我上面提到的原因,我对它们很警惕.

最后:所以基本上我要做的是通常使用原始ptr(T *)作为参数的函数我想创建一个系统,其中这些参数可以自动接受任何各种smart_ptr类型,而不必做呼叫站点的转换.我想这样做的原因是因为我认为它会通过消除转换过程使代码更具可读性(因此也略微更短,但不是很多)并且它会使重构和尝试不同的智能指针制度减少麻烦.

也许我应该把它叫做unmanaged_ptr而不是any_ptr.这将更准确地描述语义.我为这个糟糕的名字道歉.

编辑2

好的,这就是我想到的课程.我叫它dumb_ptr.

template<typename T>
class dumb_ptr {
 public:
  dumb_ptr(const dumb_ptr<T> & dm_ptr) : raw_ptr(dm_ptr.raw_ptr) { }  
  dumb_ptr(T* raw_ptr) : raw_ptr(raw_ptr) { }  
  dumb_ptr(const boost::shared_ptr<T> & sh_ptr) : raw_ptr(sh_ptr.get()) { }  
  dumb_ptr(const boost::weak_ptr<T> & wk_ptr) : raw_ptr(wk_ptr.lock().get()) { }  
  dumb_ptr(const boost::scoped_ptr<T> & sc_ptr) : raw_ptr(sc_ptr.get()) { }  
  dumb_ptr(const std::auto_ptr<T> & au_ptr) : raw_ptr(au_ptr.get()) { }  
  T& operator*() { return *raw_ptr; }
  T * operator->() { return raw_ptr; }
  operator T*() { return raw_ptr; }
 private:
  dumb_ptr() { } 
  dumb_ptr<T> operator=(const dumb_ptr<T> & x) { }
  T* raw_ptr;
};

它可以自动从常用智能指针转换,可以作为原始T *指针处理,进一步可以自动转换为T *.默认构造函数和赋值运算符(=)已被隐藏,以阻止人们将其用于除函数参数之外的任何其他内容.当用作函数参数时,可以执行以下操作.

void some_fn(dumb_ptr<A> ptr) {
  B = ptr->b;
  A a = *ptr;
  A* raw = ptr;
  ptr==raw;
  ptr+1;
}

这几乎是你想用指针做的一切.它具有与原始指针T *完全相同的语义.但现在它可以与任何智能指针一起用作参数,而无需在每个调用站点重复转换代码(.get,.lock).此外,如果您更改智能指针,则无需修复每个呼叫站点.

现在我认为这是相当有用的,我不能看到它的问题?

解决方法:

使用这样的类any_ptr,除了*和 – >之外,你几乎不能做任何其他事情.没有任务,复制构造,复制或破坏.如果这就是你所需要的,那么只需将函数作为参数写入原始指针T *,然后在你的自动指针上使用.get()或whatnot来调用它.

标签:c,smart-pointers,boost
来源: https://codeday.me/bug/20190827/1736760.html