On Friday 17 June 2005 06:24, Stefan Hundhammer wrote: ...
Maybe it is possible to hide all that confusion if it is designed and implemented properly, and maybe overloading operator.() and operator*() might help for that purpose.
But IMHO since you need to keep thinking anyway when using C++ it's a much better idea not to add yet another layer of abstraction and thus complexity and remain honest with your C++ programmers: Make it absolutely clear what is an object and what is a pointer. Don't add to the confusion. It only adds to the burden they have to carry.
This may be of interest, particularly the part about pointers and references: http://doc.trolltech.com/qq/qq13-apis.html I agree with Meister Ettrich. OSG uses reference to pass matrices to functions which modify them. That is very deceptive syntax. I believe it's much better to explicitly show that your parameter is subject to modification by using pointers. The reason for proposing the overloading of operator.(), and operator.*() is so that handles can act "just like" the objects they proxy. As it stands, classes such as boost::shared_ptr<> expose the "naked" object in order to provide access to its members using operator.(). The problem with exposing the object directly is that it's one step away from obtaining an unmanaged handle on it. Part of my reason for posting the original article is because I'm trying to develop a uniform, effective and concise approach to the general problem of managing multiple handles on a single object. I'm not yet past the apprentice level in C++ programming, and am finding this one of the more challenging aspects of working with the language. The first few sections of the following suggest that I am not the only one looking for answers in this area. http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1745.pdf The approach OSG uses is to derive many classes from a reference counted baseclass, and make destructors protected. That means that the only way to destroy such objects is by reducing the reference count to 0, and having the internal selfdestructor take care of the rest. Such objects cannot be used as automatic variables (because the destructor can't be called when they go out of scope), and can therefore be somewhat awkward to use. The osg::Referenced derivatives still allow the user to get an unmanaged handle on the object, but they make it easy to participate in the management of the object even if the object is only available as a "raw" pointer. For example, I can have a member variable of a class Bar of type osg::ref_ptr<osg::Geometry> _gometry_rptr; I can then pass the raw pointer to a function - say, a constructor - by using Foo foo = new Foo(_geometry_rptr.get()). Foo could hold onto the pointer by declaring a member osg::Geometry* _geometry_ptr; But there is no protection against Bar reducing the reference count on _geometry_rptr.get() to zero, and thus causing it to be destroyed. If that happens, Foo::_geometry_ptr; is left dangling. Since I know osg::Geometry is derived from osg::Referenced, I can replace Foo{ osg::Geometry* _geometry_ptr; } with Foo{ osg::ref_ptr<osg::Geometry> _geometry_rptr; }. In that case, if an instance of Bar deduces the reference count by 1, Foo will still have it's reference count recorded, and will not be left with a dangling pointer. This is distinct from the behavior offered by boost::shared_ptr<> (AKA std::tr1::shared_ptr<>.) boost::shared_ptr<> does not cause any direct change in the internal state of the object it owns. Rahter, it relies on direct contact with other boost::shared_ptr<> instances to communicate the ownership state. This is fairly similar to the way std::auto_ptr<> works, with the exception that std::auto_ptr<> is a single ownership handle. The counterpart to the osg::ref_ptr in boost is boost::intrusive_ptr<>. I started working out an approach to using that as the foundation of my shared object management. Unfortunately, it comes with all the same problems as the osg::Referenced, and osg::ref_ptr<>. -- Regards, Steven