游戏开发论坛

 找回密码
 立即注册
搜索
查看: 5139|回复: 11

敬请兄弟们帮忙斟酌-关于AddRef与函数返回指针

[复制链接]

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
发表于 2008-5-7 18:36:00 | 显示全部楼层 |阅读模式
敬请兄弟们帮忙斟酌-关于AddRef与函数返回指针

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
 楼主| 发表于 2008-5-7 18:46:00 | 显示全部楼层

Re:敬请兄弟们帮忙斟酌-关于AddRef与函数返回指针

尽量使用SmartPtr,可以减少对AddRef的 具体方式 的依赖性,
也方便以后的 改动。

但是,不是所有场合都可以用 SmartPtr,
而恰恰是,在关键的地方(函数调用与返回)不能用SmartPtr。

这么一来,return只有用宏解决,没有比这个方便的了。

#define RETURN_PTR(p)    (p)->AddRef(); return p;
#define RETURN_PTR(p)    return p;

...估计今晚会做出决定。。。

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
 楼主| 发表于 2008-5-7 19:05:00 | 显示全部楼层

Re:敬请兄弟们帮忙斟酌-关于AddRef与函数返回指针

归纳一下,从本质上讲,有2种上方AddRef方式和1种下方AddRef方式:

p2->AddRef();
p1->Release();
p1=p2;

p1->Release();
p2->AddRef();
p1=p2;

p1->Release();
p1=p2;
p1(p2)->AddRef();

函数返回值的时候,需要跨越函数边界,只有2种方式

p1->Release();
    p2->AddRef();
    return p2;
p1=p2; (return value)

p1->Release();
    return p2;
p1=p2; (return value)
p1(p2)->AddRef();

传递参数的时候,也要跨越函数边界,有3种方式:

p2->AddRef();
p2作为参数传递
    p1->Release();
    p1=p2;

p2作为参数传递
    p1->Release();
    p2->AddRef();
    p1=p2;

p2作为参数传递
    p1->Release();
    p1=p2;
    p2->AddRef();

//我考虑用#define解决下。

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
 楼主| 发表于 2008-5-7 19:10:00 | 显示全部楼层

Re:敬请兄弟们帮忙斟酌-关于AddRef与函数返回指针

需要这么几种宏:

1直接赋值
2赋予返回值
3返回指针
4参数传递


为了避免错误和混淆,

1直接赋值 2赋予返回值 应当可以互换使用。

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
 楼主| 发表于 2008-5-7 19:42:00 | 显示全部楼层

Re:敬请兄弟们帮忙斟酌-关于AddRef与函数返回指针

不过在想想看,
回想我以前对于COM指针的做法,
不难发现,

返回的时候AddRef是很不方便的,

OtherFunction( GetPtr() );
这样用的时候很不方便。

传入参数的时候,我想没有异议,包括com规范在内。
没有人愿意在传入参数的之前AddRef。


为了避免混淆,和SmartPtr的实现,
如果函数返回的时候 不 AddRef,
那么new 的时候,构造函数应当 m_RefCount=0;

这样唯一带来的不方便就是,
成员变量,全局变量,在new之后需要AddRef
(除非使用SmartPtr,不过一些内部指针不与外界交互,没必要SmartPtr)

(当然作为参数传递的new,不需要AddRef)

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
 楼主| 发表于 2008-5-7 19:51:00 | 显示全部楼层

Re:敬请兄弟们帮忙斟酌-关于AddRef与函数返回指针

不过,不采用COM的那种方式的话,
SmartPtr就不允许直接用在COM指针上面,除非这样:

pCOM = GetCOM();
pCOM->Release();
SmartPtr<COMInterface> sp = pCOM;
......

或者,另外封装一个SmartCOMPtr,
然后,在构造函数和operator = 中,
分2中情况进行:

SmartCOMPtr(const SmartCOMPtr<T> &sp)
{
    m_p = sp.m_p;
    if(m_p) m_p->AddRef();
}
SmartCOMPtr(T p)
{
    m_p = p; //不要AddRef
}

但是,这种做法100%保险吗?
用户获得COM 裸 指针的途径我们不能保证,(可能是“非官方”途径)
擅自认为,COM裸指针总是已经AddRef过了,这比较草率。

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
 楼主| 发表于 2008-5-7 20:02:00 | 显示全部楼层

Re:敬请兄弟们帮忙斟酌-关于AddRef与函数返回指针

另外,为了防止搞错SmartPtr和SmartCOMPtr,在debug下还需要做个check:
//#ifdef INST_DEBUG
if(Cast(L"inst::IDynamic")==null)INST_BREAK;
//#endif
//#ifdef INST_DEBUG
if( Not QueryInterface(IID_IUnkown,&p) )INST_BREAK;
//#endif

60

主题

1319

帖子

1319

积分

金牌会员

Rank: 6Rank: 6

积分
1319
发表于 2008-5-9 10:34:00 | 显示全部楼层

Re:敬请兄弟们帮忙斟酌-关于AddRef与函数返回指针

关注C++0x中,Smart Pointer基本确定引入了,不知道传说中的可选的垃圾回收机制最后会不会加进去。

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
 楼主| 发表于 2008-5-9 16:56:00 | 显示全部楼层

Re:敬请兄弟们帮忙斟酌-关于AddRef与函数返回指针

bind, 循环引用。。。
nnd,在RpgDIY(vb6.0)中运行的好好的UI类库,
在C++里遭遇了循环引用。

算了算了,一气之下,把Form,Ctrl之间全部改为weak ptr。
实际上只要保证 先解耦再删除就OK了,
而且,没有人一天到晚去拆卸控件和容器,几乎只有在创建/销毁窗体的时候才会去做。
老子也犯不着用gc,开销不小阿。总之SmartPtr,AddRef,能不用就不用。

好在3d engine里面没有bind,直接用SmartPtr,管它呢。

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
 楼主| 发表于 2008-5-9 17:17:00 | 显示全部楼层

Re:敬请兄弟们帮忙斟酌-关于AddRef与函数返回指针

就UI类库来说,这样用倒是挺不错的。就算是蔡鸟用户,一般也不会搞坏UI类库。
(如果有窗体编辑器自动生成代码,就更加安全)
万一违规内存访问了,那就看一下,有没有哪个地方没有unbind就delete掉了。

有人会问我,那么这样还需要SmartPtr和AddRef做什么??
----这是在异步Event中用的。Event并不是直接CallBack,
而是先把所有Event存入队列,然后再Peek出来。(应用层无法危害UI类库的消息处理)
然后如果处理Event,如果删除了某个Form,那么余下的Event可能会出错。
所以在Event队列中必须用SmartPtr或AddRef。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-1-22 13:55

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表