Home Help Center

IceInternal::Handle

I have a question about the IceInteral::Handle. First off should we be using it? For instance if I have created some interface IA and then derived from it and want to keep a pointer to the more derived object that has some internal interface, so:
class A : IA
{
   // some more internal interface
};

typedef IceInternal::Handle<A> APtr;

If this is considered valid. Why is Handle in the IceInternal namespace. Or should I be using the one in IceUtil and if so, are the two compatible?

Lastly, one comment about Handle. Why are the constructors not "explicit" so that, for instance, the add(...) operation in the ObjectAdapter cannot implicitly take a pointer to an Ice::Object type without complaining (which I think could be dangerous, no...)?

Regards,
Ryan

Comments

  • marcmarc FloridaAdministrators, ZeroC Staff Marc LaukienOrganization: ZeroC, Inc.Project: The Internet Communications Engine ZeroC Staff
    You should use IceUtil::Handle. It is compatible with IceInternal::Handle.

    The difference between these two is that the latter can be used even if the underlying type is only declared but not defined. However, to make this work, IceInternal::Handle requires additional code for each template instance, and is therefore better suited for generated code than for hand-written code.

    The constructor is not explicit because passing a pointer where a handle is expected is permissible. For example, you can call some_adapter.add(new SomeObjectI) without any problems.
  • Great. Thanks Marc!

    On the bit about the Handle constructor. From a dummy users perspective we tracked down a bug today which was determined to be the adapter trying to double delete an object when being destroyed. Our confusion was caused primarily by us being stupid and trying to have the object add itself into its adapter in its constructor. Something like:
     class A
    {
       A()
       {
          AdapterForA::instance()->add(this); // !!!
       }
    };
    

    I guess this is ok to do but then we also tried to keep a smart pointer reference of A around as well (which was obviously baaaaad since there is no way to link them I think?). So,
        AHandle theA(new A);
    

    Anyway, our dummy-hood may have been a little less certain if we were forced to write class A like
          AdapterForA::instance()->add(AHandle(this));
    

    And it really doesn't add that much effort I think?

    V/R,
    Ryan
  • marcmarc FloridaAdministrators, ZeroC Staff Marc LaukienOrganization: ZeroC, Inc.Project: The Internet Communications Engine ZeroC Staff
    I'm not sure I understand. You can of course also keep a smart pointer instance. Do you have a complete example that demonstrates the problem? I can't see anything wrong in the code segments.

    AdapterForA::instance()->add(AHandle(this));

    Is equivalent to:

    AdapterForA::instance()->add(this);

    The only difference is that in the first case, you are creating a smart pointer explicitly, while in the second case the compiler creates a smart pointer as a temporary. But with respect to reference counts and memory management, both statements are equivalent.
  • michimichi Member Michi HenningOrganization: Triodia TechnologiesProject: I have a passing interest in Ice :-) ✭✭✭
    I agree -- this should work because the reference count is kept in the object, not in the handle. If you can reproduce this in a small example, I'd be interested in having a look at it.

    Cheers,

    Michi.
  • marcmarc FloridaAdministrators, ZeroC Staff Marc LaukienOrganization: ZeroC, Inc.Project: The Internet Communications Engine ZeroC Staff
    As an aside, if you have used CORBA and its _var types before, then this is most likely the source of confusion. The _var types do very weird things, namely to "assume ownership" if you assign a pointer of the underlying type. Ice handles don't do this, they behave like "normal" reference-counted smart pointers. No "ownership" is assigned when you assign a plain C++ pointer to an Ice smart pointer. Here is an example:

    The following is illegal in CORBA:

    T* p = ...;
    T_var hande1(p);
    T_var hande2(p);
    T_var hande3(p);

    That's because of this brain-dead concept in the CORBA C++ mapping of "assigning ownership". However, the following is perfectly legal in Ice:

    T* p = ...;
    TPtr hande1(p);
    TPtr hande2(p);
    TPtr hande3(p);

    I can only guess what the authors of the _var type were trying to achieve. Perhaps they started out with something similar to std::auto_ptr, and then added reference counting, ending up with a solution that is neither here nor there...
  • Ah, reference count is in Object!!

    Hi guys,

    Ok. I see what you are doing. Every Object type holds the reference count. I assumed you were implementing something close to the boost/shared_ptr. Which reminds me. That was where our error was (I didn't accurately write up our error above). We had mistakenly done something like this:
    class A
    {
       A() : IA
       {
          AdapterForA::instance()->add(A); 
       }
    }
    
    // In code later on:
    
    typedef boost::shared_ptr<A> APtr;
    APtr theA(new A);
    

    I think early on. before we discovered the IceUtil::Handle, we had assumed that we were not supposed to be typedef-ing our own IceInternal::Handle types so that's when I decided to use the boost shared_ptr (not realizing under the covers another smart pointer type was being used). Hindsight is 20-20 of course. Definitely looks like a Nubian error now! :o

    Thanks for your help,
    Ryan
  • michimichi Member Michi HenningOrganization: Triodia TechnologiesProject: I have a passing interest in Ice :-) ✭✭✭
    Originally posted by marc
    I can only guess what the authors of the _var type were trying to achieve. Perhaps they started out with something similar to std::auto_ptr, and then added reference counting, ending up with a solution that is neither here nor there...

    The historical reason is that some submitters (notably IBM) insisted on having a C++ mapping that was binary compatible with a C mapping. So, putting reference counts inside something like a class or a struct wasn't an option, which is why the _var type work the way they do. (Of course, that's no consolation when you are stuck with them.)

    The irony is that, despite all of IBM's insistence, the C++ mapping has never existed in a form that could be made binary compatible with the C mapping. The net effect, of course, is that users ended up with a severely compromised C++ mapping because of this insistency on compatibility with C but, at the same time, got a mapping that never provided that compatibility. Talk about getting the worst of both worlds...
    Originally posted by RyanFogarty
    I think early on. before we discovered the IceUtil::Handle, we had assumed that we were not supposed to be typedef-ing our own IceInternal::Handle types so that's when I decided to use the boost shared_ptr (not realizing under the covers another smart pointer type was being used).

    No, it's perfectly OK to use IceUtil::Handle to make your own typedefs (and the doc shows how to do that in a number of places). The whole point of IceUtil::Handle is that you get a smart pointer that is useful not only for Ice-generated classes, but is useful in general. However, you should not use anything in the IceInternal namespace in your application code. As the name suggests, that's stuff that is internal to Ice, and we need to be free to change that as we see fit without notice.

    Cheers,

    Michi.
Sign In or Register to comment.