addref去掉就出错,
addref和release 是一对用
这样可以保证内存中只有一个程序进程
当计数器为0时,可以自动释放,

解决方案 »

  1.   

    我试着按照我的意思改了程序,和原来程序的运行效果一样。
    bobqi(灰冷) ,我这样改,AddRef和Release应该仍然成对。
    但是我有点怕是不是我有没考虑到的地方,这样改是不是在别的情况下会出错。
      

  2.   

    你已经知道“先AddRef是为了防止Init中出现错误时导致外部对象自动销毁”,所以在Init代码中没有错误时效果是一样的。代码的健壮性是非常重要的,所以才有“异常”技术的出现。
      

  3.   

    有些语言,例如Object Pascal,它的变量是自动释放的,不能如C++般灵活控制。这时候,灵活的C只好迁就Pascal,所以一个借口指针在一个变量的作用域里,AddRef与Release都是一对一对的。
      

  4.   

    Buma(灌水)兄:先AddRef是为了避免Init函数中调用Release函数后,存在m_Ref为0而释放
    外部对象的可能。我是把Init函数里的Release移到CreateInstance里,这样可以
    省却一对AddRef,Release。musicdancer(饭盆)兄,我这样是不是并没有破坏这个保险措施?俺还有另一个问题:
       p107-p108关于CB的析构函数的讨论的疑点:
       析构函数里面为何要使用  m_Ref=1;
                             IUnknown *pUnknownOuter = this;
                             pUnknownOuter->AddRef();
       直接对m_Ref进行赋值2不就行了么?
      

  5.   

    你要知道,这个程序是你自己编的,你控制了一切,那你当然觉可以做到简洁一些.然而,不幸的是,我们不能假设其他人在使用你的组件的时候和你一样的想法,我们必须坚持一定的原则和作最坏的假设.所以别人不知道你究竟怎样处理那对计数,就假设你符合com一般的原则.
      

  6.   

    你上面说的那个
    m_Ref=1;                      
    IUnknown *pUnknownOuter = this;
    pUnknownOuter->AddRef();  //这里面加的是m_Ref?
      
      

  7.   

    谢谢musicdancer(饭盆)兄:您说的对,我刚开始学,一些概念还不是很清楚,我想 我只要
    提供接口给外面,只要一个组件内部能按照com规范完成功能,至于组件内部实现细节用户
    不必了解。像这个例子中涉及的init和createinstance函数都是组件内部的事。那个IUnknown *pUnknownOuter = this;
    pUnknownOuter->AddRef();
    我以为是调用了外部对象的AddRef,对m_Ref加一,不知道对不对?
      

  8.   

    关于m_ref.
    就这3句来说,你是对的.
    因为没看到源程序是怎样,我也不太明白这里的意思.
      

  9.   

    按你的方法:
    把Init函数最后的pUnknownOuter->Release();语句和CreateInstance
    函数中的 pObj->AddRef();语句去掉
    在这个程序里没有问题,只要你知道init中干了什么.
    引用计数com没有作更多的要求,唯一要求是给记清楚了,不让内存泄漏.:)我前面在楼上说的好像不太对题,:(.
      

  10.   

    书上写的是对的,我想其实老潘也没讲清楚,
    在生成之后立即addref
    是为了防止访问竞争,
    即有外部对象的接口调用了pUnkown->release(),
    导致外部对象的引用计数为0,
    个人理解不知道对不对?
      

  11.   

    to chenyf(卖女孩的小火柴)
      我刚才就在想什么情况下,刚生成对象,外部对象的接口就调用了pUnkown->release().
      
    由于没看源代码,搞不清楚这里pUnknownOuter和pObj的关系.
    个人觉得这本书在有些方面(比如关于包容聚合等)轻描淡写了些(老潘太厉害了).
    看看 <<inside com>>比较爽朗些.
    如果你再遇到问题(比如,在聚合里很多初学者会遇到一个想不通的死循环),可以先查找一下.
      

  12.   

    死循环也是因为老潘的聚合方法过于昏涩,
    用一个强制转换替换vtable,
    com本质论的例子就很简明,
    C++学的不好也马马虎虎看得懂
      

  13.   

    chenyf(卖女孩的小火柴),你的理解是对的,确实是为了防止访问竞争。BTW,你是人贩子?:)
    musicdancer(饭盆):
    我有inside com的电子版,觉得比pam的通俗易懂点。同学还有本《本质论》,听说恨难,
    真是学无止境啊:(。聚合是我碰到的第一个难点,啃了好久才明白。你们有没有用com实际做过项目啊?感觉咋样?
      

  14.   

    还想问一下,我咋从来没收到过csdn的邮件啊,是不是没有邮件服务?
      

  15.   

    没用com做过项目,不过我喜欢com.csdn早就不发邮件了,可能负担太重.
      

  16.   

    很高兴看到大家的讨论,有几个疑点解释一下,希望能够对你们有所帮助。1 析构函数的处理不是为了防止访问竞争,而是为了AddRef和Release调用配对。书上有解释。但是很多人不明白,我也不希望在这种太细节的地方让大家钻牛角。但这确实是有必要的。2 聚合的实现方法有多种,MFC和ATL的实现与这本书不同,不过这些实现的原理都是一致的。内部对象实现两个IUnknown是COM规范的要求,也是COM对象IUnknown接口一致性的要求。具体实现细节在不同的实现方法中表现形式不见得相同,但是本质是一致的。相比较而言,用内嵌类实现COM接口的方法(也就是MFC采用的方法)要直观一些,而用多继承的方法涉及到过多C++知识,显得晦涩一些。
      

  17.   

    没想到能把潘爱民老师引来。谢谢您的指教。再问一下:
    1、不知道我在上面关于AddRef和Release的想法对不对?
    2、《本质论》是不是真的很难,需要一些com基础才行?
      

  18.   

    答复daydream,
    1 AddRef和Release是必需的,为了避免引用计数回到0的情况。在初始化(即Init函数)的时候,有可能要把自己的接口指针交给别的程序,所以加一层保护是必要的。引用计数是共享资源的有效实现技术,而这种保护技术又是一种通常的技术,并不局限于COM的聚合模型。2 “Essential COM”并不难,但要真正理解书上的内容确实需要扎实的基础。