Re: returning references
On Jan 6, 12:14 pm, Michael DOUBEZ <michael.dou...@free.fr> wrote:
Daniel T. a =E9crit :
[...]
When James said the above, I took it to mean something like
the example below.
class Foo {
public:
const Bar& get() const;
};
void bad_client( Foo& foo ) {
const Bar* b = &foo.get();
// then do things, assuming that 'b' will continue to be
// valid no matter what I may do to 'foo'.
}
I consider such code to be inherently dangerous... When what
is returned is a const-reference to internal state, the
calling code shouldn't assume 'b's validity even past the
';' of the get call.
That depends on the contract you have with Foo. If it is a
singleton or a scoped_ptr<> by example, there is nothing
wrong.
More generally: part of the problem may be just one of
semantics: what is meant by "internal state". But my fealing is
that the statement as presented by Daniel T is an over
simplification---the issues are just too complicated to be
covered by simple cliches. I'd be interesting in hearing his
comments on the following (which is a very frequent idiom in
servers in business applications):
class EntityObject : private boost::uncopiable
{
public:
virtual ~EntityObject() {}
virtual std::string id() const = 0 ;
// ...
} ;
class EntityObjectDataBase
{
private:
struct EntityObjectOrder
{
bool operator()(
EntityObject* lhs,
EntityObject* rhs ) const
{
return lhs->id() < rhs->id() ;
}
}
typedef std::set< EntityObject*, EntityObjectOrder >
DataBase ;
DataBase myData ;
public:
EntityObject* get( std::string const& id ) const
{
DataBase::const_iterator
entry = myData.find( id ) ;
return entry != myData.end()
? *entry
: NULL ;
}
// functions for insertion and removal...
} ;
Note that the object pointed to by the return value of
EntityObjectDataBase::get() definitely contains state relevant
to the class invariants of the myData member of
EntityObjectDataBase; presumable, one could even write a derived
EntityObject in which non-const member functions modified the
value returned by EntityObject::id(). Obviously, of course, one
doesn't want to do that, but there's nothing in the language
which would prevent it. The problem here is simple: the
language (and simple additional rules) can only go so far in
protecting against stupid errors. The requirement that I call
get() (and check for null) in every single statement which uses
an object is simply not tenable, and saving the pointer returned
by get() is seems to be a case of the sort of thing Daniel T
seems to be saying one should never do.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34