在c++中使用引用计数,有什么好的办法解决循环引用问题

137 views
Skip to first unread message

yaya...@gmail.com

unread,
Apr 7, 2008, 11:21:15 PM4/7/08
to TopLanguage
在c++中使用引用计数,有什么好的办法解决循环引用问题。

鋆邓

unread,
Apr 7, 2008, 11:26:23 PM4/7/08
to pon...@googlegroups.com
使用好的引用模型,不要产生循环引用问题
建立树型或分层型的对象网络结构,从上层到下层的引用不使用引用计数

2008/4/8 yaya...@gmail.com <yaya...@gmail.com>:
在c++中使用引用计数,有什么好的办法解决循环引用问题。


alai

unread,
Apr 7, 2008, 11:28:30 PM4/7/08
to pon...@googlegroups.com
参照shared_ptr和weak_ptr

在 08-4-8,yaya...@gmail.com<yaya...@gmail.com> 写道:
> 在c++中使用引用计数,有什么好的办法解决循环引用问题。
> >
>

vczh

unread,
Apr 7, 2008, 11:39:15 PM4/7/08
to TopLanguage
引用计数无法解决循环引用问题,请换方法。

鋆邓

unread,
Apr 7, 2008, 11:43:03 PM4/7/08
to pon...@googlegroups.com
恩,所以我的建议就是,不要产生循环引用问题……

2008/4/8 vczh <Geniu...@gmail.com>:
引用计数无法解决循环引用问题,请换方法。


yzzrn

unread,
Apr 8, 2008, 12:37:49 AM4/8/08
to TopLanguage
同意.
把循环依赖解了就不会循环引用了.

On 4月8日, 上午11时43分, "鋆邓" <tdzl2...@gmail.com> wrote:
> 恩,所以我的建议就是,不要产生循环引用问题……
>
> 2008/4/8 vczh <GeniusV...@gmail.com>:
>
> > 引用计数无法解决循环引用问题,请换方法。

李扬

unread,
Apr 8, 2008, 1:01:35 AM4/8/08
to pon...@googlegroups.com
这个只是理论上可行的办法。不论是weakptr还是良好的设计。但是在一个不断扩展的系统中需要有一种自动化的技术去检查循环依赖的问题。请问有好的办法吗?

在08-4-8,yzzrn <yz...@21cn.com> 写道:

Googol Lee

unread,
Apr 8, 2008, 2:00:57 AM4/8/08
to pon...@googlegroups.com
gc?

在 08-4-8,李扬<yaya...@gmail.com> 写道:


--
新的理论从少数人的主张到一统天下,并不是因为这个理论说服了别人抛弃旧观点,而是因为一代人的逝去。

My blog: http://googollee.blog.163.com

qq wu

unread,
Apr 8, 2008, 3:33:55 AM4/8/08
to pon...@googlegroups.com
shared_ptr 和weak_ptr已经进入标准了, 还这么排斥啊?
有时候虽然可以解依赖, 但弱引用也是很有用的,  比如说, 它可以作为一个指针的观察者

 
在08-4-8,Googol Lee <goog...@gmail.com> 写道:

red...@gmail.com

unread,
Apr 8, 2008, 4:06:59 AM4/8/08
to pon...@googlegroups.com
这都是一些用起来容易出错的技术---- 或许当时代码没有错, 但是代码演变过程
中, 这些点都是很危险的.

没有 gc 的时候, 设计别的对象释放的机制, 例如打 mark, 然后在系统 idle 循
环中进行清理之类的, 都可靠得多.

如果我选择用 C++ 做一个复杂一点的项目, 则倾向于不是大框架用脚本, C++ 只
是用来做部件, 这样就有别的生存期管理技术.

我已经不想和 C++ 里面的各种复杂的东西做斗争了. 要性能或者要实现底层代码,
就直接用 C 写 不怎么 OO 的程序, 反正这种代码规模不大, 加上不怎么 OO, 不
会有复杂的对象关系和生存期管理 ; 高层一些的代码, 要么用脚本语言, 要么用 D.


qq wu wrote:
> shared_ptr 和weak_ptr已经进入标准了, 还这么排斥啊?
> 有时候虽然可以解依赖, 但弱引用也是很有用的, 比如说, 它可以作为一个指针
> 的观察者
>

> 在08-4-8,*Googol Lee* <goog...@gmail.com
> <mailto:goog...@gmail.com>> 写道:
>
> gc?
>
> 在 08-4-8,李扬<yaya...@gmail.com <mailto:yaya...@gmail.com>>
> 写道:
> > 这个只是理论上可行的办法。不论是weakptr还是良好的设计。但是在一
> 个不断扩展的系统中需要有一种自动化的技术去检查循环依赖的问题。请问
> 有好的办法吗?
> >
> >
> > 在08-4-8,yzzrn <yz...@21cn.com <mailto:yz...@21cn.com>> 写道:


> >
> > > 同意.
> > > 把循环依赖解了就不会循环引用了.
> > >
> > > On 4月8日, 上午11时43分, "鋆邓" <tdzl2...@gmail.com

> <mailto:tdzl2...@gmail.com>> wrote:
> > > > 恩,所以我的建议就是,不要产生循环引用问题……
> > > >
> > > > 2008/4/8 vczh <GeniusV...@gmail.com

> <mailto:GeniusV...@gmail.com>>:
> > > >
> > > > > 引用计数无法解决循环引用问题,请换方法。
> > > >
> > >
> >
>

qq wu

unread,
Apr 8, 2008, 4:11:36 AM4/8/08
to pon...@googlegroups.com
使用shared_ptr 和weak_ptr更重要的一点是:从一开始就进行语义上的区分,这样防止产生错误的设计。
以用一个成员函数作为回调函数为例,这时候用原生指针容易产生野指针,用shared_ptr又会援用的对象生命期,显然这时候,weak_ptr才是合适的。
 
在08-4-8,qq wu <wuq...@gmail.com> 写道:

李扬

unread,
Apr 9, 2008, 10:54:55 PM4/9/08
to pon...@googlegroups.com
redsea 的话深合我心啊。。。我郁闷到死。现在看c++都头大。一大堆乱七八糟的东西。用c++开发大规模程序,不使用一些扩展技术真是受罪。

李扬

unread,
Apr 9, 2008, 10:56:08 PM4/9/08
to pon...@googlegroups.com


在08-4-8,red...@gmail.com <red...@gmail.com> 写道:
这都是一些用起来容易出错的技术---- 或许当时代码没有错, 但是代码演变过程
中, 这些点都是很危险的.

没有 gc 的时候, 设计别的对象释放的机制, 例如打 mark, 然后在系统 idle 循
环中进行清理之类的, 都可靠得多.

能具体说下怎么进行标记清理?

red...@gmail.com

unread,
Apr 9, 2008, 11:42:22 PM4/9/08
to pon...@googlegroups.com
李扬 wrote:
>
>
> 在08-4-8,*red...@gmail.com <mailto:red...@gmail.com>*
> <red...@gmail.com <mailto:red...@gmail.com>> 写道:
>
> 这都是一些用起来容易出错的技术---- 或许当时代码没有错, 但是代码演

> 变过程
> 中, 这些点都是很危险的.
>
> 没有 gc 的时候, 设计别的对象释放的机制, 例如打 mark, 然后在系统
> idle 循
> 环中进行清理之类的, 都可靠得多.
>
> 能具体说下怎么进行标记清理?
>

拿 Windows 客户端单线程程序举例, 由于各种对象之间互相调用, 以及可能的
sendmessage, 在消息处理过程中是否能够 delete 对象, 是搞不清楚的, 因此目
标对象的成员函数可能正在 call stack 中的, 即使目前的代码, delete 是安全
的, 但是这样的实现, 也非常脆弱, 改天调用链一改动, 可能就崩溃了 ---- 当
然, 也可以进行一堆严格的调用约定, 使得某些外层, 并且不允许被递归调用的函
数可以 delete 对象, 这种 函数 delete 对象之后, 不允许调用一般的函数 ----
这样同样麻烦, 脆弱性的改善也很有限.

用 com 技术代替delete 是可以的, C++ 用 com 虽然繁琐, 但是还不是很脆弱;
另外一个方法就是, 不再需要一个对象的时候, 不要立刻delete, 而是做一个标
记, 或者是往一个全局队列中登记一下, 等执行到主窗口 dispatchMessage 的那
个函数的时候 (如果你还担心这个也会递归进入, 那么加入一个递归次数计数器,
表明是最外层调用的时候, 才做下面的事情), 处理完所有的消息, 就检查需要释
放的对象, 在这里进行释放, 就安全了, 没有 call stack 的问题.

如果是多线程, 就麻烦一些了, 需要定义一些线程之间的同步协议, 这就看具体的
应用了.

服务器程序也是一样, 它会有一个select/poll 的 loop, 在这个最高层次的 loop
做这个事情, 就安全了.

C++ 的 autoptr, weakptr, 一堆概念, 烦啊, 类似的这些影响全局的东西, 如果
每引入一个, 程序可靠性降低5%, 多引入几个, 可靠性就越发低了. 还是简单为王.

李扬

unread,
Apr 9, 2008, 11:50:01 PM4/9/08
to pon...@googlegroups.com
com有循环引用问题。搞得头大在对象树很复杂的情况下。现在我就想有个能够自动检测这些引用环的机制。而不是要人肉去确保这些东西。
在08-4-10,red...@gmail.com <red...@gmail.com> 写道:

K.L.

unread,
Apr 10, 2008, 10:30:28 AM4/10/08
to TopLanguage
有的时候循环引用是由成员函数的bind引起的,shared_ptr被藏到functor的被type-erase的成员中了,很隐蔽,而
weak_ptr又不能直接用来bind,这个问题有没有好的办法?

On 4月8日, 下午4时11分, "qq wu" <wuqq...@gmail.com> wrote:
> 使用shared_ptr 和weak_ptr更重要的一点是:从一开始就进行语义上的区分,这样防止产生错误的设计。
> 以用一个成员函数作为回调函数为例,这时候用原生指针容易产生野指针,用shared_ptr又会援用的对象生命期,显然这时候,weak_ptr才是合适的。
>
> 在08-4-8,qq wu <wuqq...@gmail.com> 写道:
>
>
>
>
>
> > shared_ptr 和weak_ptr已经进入标准了, 还这么排斥啊?
> > 有时候虽然可以解依赖, 但弱引用也是很有用的, 比如说, 它可以作为一个指针的观察者
>
> > 在08-4-8,Googol Lee <googol...@gmail.com> 写道:
>
> > > gc?
>
> > > 在 08-4-8,李扬<yayany...@gmail.com> 写道:
>
> > > 这个只是理论上可行的办法。不论是weakptr还是良好的设计。但是在一个不断扩展的系统中需要有一种自动化的技术去检查循环依赖的问题。请问有好的办法吗?
>
> > > > 在08-4-8,yzzrn <yz...@21cn.com> 写道:
>
> > > > > 同意.
> > > > > 把循环依赖解了就不会循环引用了.
>
> > > > > On 4月8日, 上午11时43分, "鋆邓" <tdzl2...@gmail.com> wrote:
> > > > > > 恩,所以我的建议就是,不要产生循环引用问题......
>
> > > > > > 2008/4/8 vczh <GeniusV...@gmail.com>:
>
> > > > > > > 引用计数无法解决循环引用问题,请换方法。
>
> > > --
> > > 新的理论从少数人的主张到一统天下,并不是因为这个理论说服了别人抛弃旧观点,而是因为一代人的逝去。
>
> > > My blog:http://googollee.blog.163.com- 隐藏被引用文字 -
>
> - 显示引用的文字 -

vczh

unread,
Apr 10, 2008, 12:39:56 PM4/10/08
to TopLanguage
请不要用C#的方法来设计C++。要bind的话,那么不要用shared_ptr,让被bind的东西在释放的时候自己去解bind。
> > - 显示引用的文字 -- 隐藏被引用文字 -
>
> - 显示引用的文字 -

qq wu

unread,
Apr 10, 2008, 12:50:46 PM4/10/08
to pon...@googlegroups.com
这个问题我也遇到过, 费了半天的劲才找到这个bug,
我解决的办法是定义一个适配器类:
template <class T, class MemFun> struct weak_functor
{
  MemFun f_;
  weak_ptr<T> p_;
 
  weak_fn(MemFun f,  shared_ptr const& p) : f_(f), p_(p) {} 
 
  void operator()  const
 { if (shared_ptr<T> ptr = p_.lock() (ptr.get()->*f_)(); }
 
  template <class P1> void operator(P1& p1)  const
  { if (shared_ptr<T> ptr = p_.lock()) (ptr.get()->*f_)(p1); }
 
  template <class P1, class P2> void operator(P1& p1, P2& p2)  const
  { if (shared_ptr<T> ptr = p_.lock()) (ptr.get()->*f_)(p1, p2); }
 
  // and more arguments...
};
 
template <class T, class MemFun> inline weak_functor<T, MemFun>
weak_fn(MemFun f, shared_ptr<T> const& p)
{
  return weak_functor<T, MemFun>(f, p);
}
 
于是就可以这样使用:
shared_ptr<Obj> pObj;
bind(weak_fn(&Obj::fun, pObj), arg1, arg2);
 
由于我一般很少使用返回值, 所以就忽略它了, 如果要使用返回值, 可以在weak_functor使用boost::result_of进行推导.
 

 
在08-4-10,K.L. <xxxK....@gmail.com> 写道:

qq wu

unread,
Apr 10, 2008, 12:52:02 PM4/10/08
to pon...@googlegroups.com
上面那个构造函数写错了...

在08-4-11,qq wu <wuq...@gmail.com> 写道:

K.L.

unread,
Apr 13, 2008, 9:14:21 PM4/13/08
to TopLanguage
想到了,用ref(shared_ptr<T>)作为bind参数就行了。只要保证shared_ptr<T>的实际所有者比functor的生命期
长。

On 4月11日, 上午12时52分, "qq wu" <wuqq...@gmail.com> wrote:
> 上面那个构造函数写错了...
>
> 在08-4-11,qq wu <wuqq...@gmail.com> 写道:
>
>
>
>
>
> > 这个问题我也遇到过, 费了半天的劲才找到这个bug,
> > 我解决的办法是定义一个适配器类:
> > template <class T, class MemFun> struct weak_functor
> > {
> > MemFun f_;
> > weak_ptr<T> p_;
>
> > weak_fn(MemFun f, shared_ptr const& p) : f_(f), p_(p) {}
>
> > void operator() const
> > { if (shared_ptr<T> ptr = p_.lock() (ptr.get()->*f_)(); }
>
> > template <class P1> void operator(P1& p1) const
> > { if (shared_ptr<T> ptr = p_.lock()) (ptr.get()->*f_)(p1); }
>
> > template <class P1, class P2> void operator(P1& p1, P2& p2) const
> > { if (shared_ptr<T> ptr = p_.lock()) (ptr.get()->*f_)(p1, p2); }
>
> > // and more arguments...
> > };
>
> > template <class T, class MemFun> inline weak_functor<T, MemFun>
> > weak_fn(MemFun f, shared_ptr<T> const& p)
> > {
> > return weak_functor<T, MemFun>(f, p);
> > }
>
> > 于是就可以这样使用:
> > shared_ptr<Obj> pObj;
> > bind(weak_fn(&Obj::fun, pObj), arg1, arg2);
>
> > 由于我一般很少使用返回值, 所以就忽略它了, 如果要使用返回值, 可以在weak_functor使用boost::result_of进行推导.
>
> > 在08-4-10,K.L. <xxxK.L....@gmail.com> 写道:
>
> > > 有的时候循环引用是由成员函数的bind引起的,shared_ptr被藏到functor的被type-erase的成员中了,很隐蔽,而
> > > weak_ptr又不能直接用来bind,这个问题有没有好的办法?
>
> > > On 4月8日, 下午4时11分, "qq wu" <wuqq...@gmail.com> wrote:
> > > > 使用shared_ptr 和weak_ptr更重要的一点是:从一开始就进行语义上的区分,这样防止产生错误的设计。
>
> > > 以用一个成员函数作为回调函数为例,这时候用原生指针容易产生野指针,用shared_ptr又会援用的对象生命期,显然这时候,weak_ptr才是合适的。
>
> > > > 在08-4-8,qq wu <wuqq...@gmail.com> 写道:
>
> > > > > shared_ptr 和weak_ptr已经进入标准了, 还这么排斥啊?
> > > > > 有时候虽然可以解依赖, 但弱引用也是很有用的, 比如说, 它可以作为一个指针的观察者
>
> > > > > 在08-4-8,Googol Lee <googol...@gmail.com> 写道:
>
> > > > > > gc?
>
> > > > > > 在 08-4-8,李扬<yayany...@gmail.com> 写道:
>
> > > 这个只是理论上可行的办法。不论是weakptr还是良好的设计。但是在一个不断扩展的系统中需要有一种自动化的技术去检查循环依赖的问题。请问有好的办法吗?
>
> > > > > > > 在08-4-8,yzzrn <yz...@21cn.com> 写道:
>
> > > > > > > > 同意.
> > > > > > > > 把循环依赖解了就不会循环引用了.
>
> > > > > > > > On 4月8日, 上午11时43分, "鋆邓" <tdzl2...@gmail.com> wrote:
> > > > > > > > > 恩,所以我的建议就是,不要产生循环引用问题......
>
> > > > > > > > > 2008/4/8 vczh <GeniusV...@gmail.com>:
>
> > > > > > > > > > 引用计数无法解决循环引用问题,请换方法。
>
> > > > > > --
> > > > > > 新的理论从少数人的主张到一统天下,并不是因为这个理论说服了别人抛弃旧观点,而是因为一代人的逝去。
>
> > > > > > My blog:http://googollee.blog.163.com-隐藏被引用文字 -
>
> > > > - 显示引用的文字 -- 隐藏被引用文字 -
>
> - 显示引用的文字 -

qq wu

unread,
Apr 14, 2008, 10:35:31 AM4/14/08
to pon...@googlegroups.com
那你直接使用原始指针就行了, 还要智能指针, 再加一个ref......
 
在08-4-14,K.L. <xxxK....@gmail.com> 写道:

red...@gmail.com

unread,
Apr 14, 2008, 10:57:56 AM4/14/08
to pon...@googlegroups.com
答得有意思 :)

哈哈.

不过老实说, 由于 OO 编程, method代码都是一小碎片一小碎片的, 对象之间互相
引用, 互相 call, callback 也多, 不支持 gc 还是太痛苦.

过程设计和编程的话, 函数之间的调用关系简单很多(虽然函数内部的实现可能痛
苦一些, 例如什么switch), 内存管理简单一些.


qq wu wrote:
> 那你直接使用原始指针就行了, 还要智能指针, 再加一个ref......
> 在08-4-14,*K.L.* <xxxK....@gmail.com <mailto:xxxK....@gmail.com>>

hyifeng

unread,
Apr 14, 2008, 8:43:53 PM4/14/08
to TopLanguage
什么时候必须要用shared_ptr?
一直以来没遇到过这种复杂的生命周期。
我习惯于大量使用栈对象,或自释放容器,基本上都能划出一个稳定的释放点。
很想知道大家使用shared_ptr的动机是什么。

On 4月14日, 下午10时57分, red...@gmail.com wrote:
> 答得有意思 :)
>
> 哈哈.
>
> 不过老实说, 由于 OO 编程, method代码都是一小碎片一小碎片的, 对象之间互相
> 引用, 互相 call, callback 也多, 不支持 gc 还是太痛苦.
>
> 过程设计和编程的话, 函数之间的调用关系简单很多(虽然函数内部的实现可能痛
> 苦一些, 例如什么switch), 内存管理简单一些.
>
> qq wu wrote:
> > 那你直接使用原始指针就行了, 还要智能指针, 再加一个ref......
> > 在08-4-14,*K.L.* <xxxK.L....@gmail.com <mailto:xxxK.L....@gmail.com>>

翁翊成

unread,
Apr 14, 2008, 9:18:05 PM4/14/08
to pon...@googlegroups.com
楼上的说的很对,尽量使用栈变量,不过也还是有时候会用到智能指针来替代原始指针管理堆变量。比如,要动态建立一个面向接口的继承体系,用户根据需要动态建立新的实现对象替换前一个,这时如果使用简单的auto_ptr<>或者scoped_ptr<>就可以很好的管理该指针。
再有,利用OO设计原则和设计模式可以减少ls的ls所说的对象之间互相引用次数。

在08-4-15,hyifeng <hyi...@gmail.com> 写道:

K.L.

unread,
Apr 15, 2008, 8:05:51 AM4/15/08
to TopLanguage
不一样的,shared_ptr可能会reset,用raw pointer可能会出现野指针,而这是很严重的问题。

至于什么时候用shared_ptr,这个叫用对象管理资源,提供系统可靠性。

On 4月14日, 下午10时35分, "qq wu" <wuqq...@gmail.com> wrote:
> 那你直接使用原始指针就行了, 还要智能指针, 再加一个ref......
>
> 在08-4-14,K.L. <xxxK.L....@gmail.com> 写道:

翁翊成

unread,
Apr 15, 2008, 9:50:57 AM4/15/08
to pon...@googlegroups.com
其实shared_ptr何时使用在boost的文档里已经说的挺详细了,可以去参看一下。

在08-4-15,K.L. <xxxK....@gmail.com> 写道:

李扬

unread,
Apr 16, 2008, 2:15:01 AM4/16/08
to pon...@googlegroups.com
呵呵呵,提个假设,如果我们是在使用com对象了?那么那些复杂的c++技巧。或者说栈对象好像都不太管用了吧?这个时候有什么好的办法了?

在08-4-15,翁翊成 <wen...@gmail.com> 写道:

qq wu

unread,
Apr 16, 2008, 2:34:49 AM4/16/08
to pon...@googlegroups.com
1)不一样的领域,不同的阶段,对于技术的认识和使用都是不同的,选择自己合适的就行了。
2)TO K.L: ref<shared_ptr<T>>只不过是shared_ptr<T>* 的另一种形式,同样可能会出现野指针。shared_ptr使用不当,也可能出现问题,而且更难调试。
 
在08-4-16,李扬 <yaya...@gmail.com> 写道:

翁翊成

unread,
Apr 16, 2008, 5:05:48 AM4/16/08
to pon...@googlegroups.com
com对象自己就提供了RefCount指针

在08-4-16,qq wu <wuq...@gmail.com> 写道:
Reply all
Reply to author
Forward
0 new messages