
Oleg Fedtchenko wrote:
But the owner may be not an immediate class-container-of-the-member or its derivative but any arbitrary class like this:
class A { public: WORD m_wData; };
class B { public: A a;
friend shared_ptr<WORD> GetData( shared_ptr<B> this_ ) { return shared_ptr<WORD>( &this_->a.m_wData, boost::bind( &shared_ptr<A>::reset, this_ ) ); } };
In this case we must create overridden functions for every owner type to correctly specify pointer to a member.
Yes.
And what about when A::m_wData is private?
Well, it depends on the actual level of privacy. Clearly a member whose address is always exposed to the world isn't really private, regardless of its access specifier. But that aside, depending on the level of coupling between A and B, B should either be a friend of A, or it must go via an analogous mechanism to obtain WORD* from A*: // in A friend shared_ptr<WORD> GetData( shared_ptr<A> this_ ) { return shared_ptr<WORD>( &this_->m_wData, boost::bind( &shared_ptr<A>::reset, this_ ) ); } // in B friend shared_ptr<WORD> GetData( shared_ptr<B> this_ ) { shared_ptr<A> pa( &this_->a, boost::bind( &shared_ptr<B>::reset, this_ ) ); return GetData( pa ); } Yes, this is not very efficient. But it's encapsulated (which is pretty much the only point of making the data members "private" in this case.) That is, you can change B::a from A a; to shared_ptr<A> pa; without changing the client code, or you could even generate the A dynamically inside GetData. Similarly, you can change A::m_wData to shared_ptr<WORD>. Another shared_ptr advantage is that weak_ptr works.
Don't you think this is the better variant:
template<class Z> shared_ptr<WORD> A::GetData( shared_ptr<Z> owner ) { return shared_ptr<WORD>( &m_wData, boost::bind( &shared_ptr<Z>::reset, owner ) ); }
This is error-prone. I can pass any shared_ptr as an owner, regardless of whether it actually owns *this.