Re: returning references
On Jan 6, 12:27 am, "Daniel T." <danie...@earthlink.net> wrote:
jkherci...@gmx.net wrote:
Daniel T. wrote:
James Kanze <james.ka...@gmail.com> wrote:
"Daniel T." <danie...@earthlink.net> wrote:
A map does not return a non-const reference to any internal
state, so I don't see how that relates in any way.
std::map certainly does return references to internal state, as
does every other map I've every seen or heard of.
Really, could you give an example? Maybe I'm mistaken...
std::map< int, int > the_map;
...
the_map[5] = 6; // the_map[5] returns an int&.
I conjecture that the two of you are in disagreement about whether
that is an "internal state" of the map. Since I have no idea what
"internal state" is supposed to mean with regard to std::map, I
will not offer an opinion.
Right, that is not internal state, I define "internal state"
as state that is part of the invariant of the class. Does
changing the state of the object returned by map::operator[]
have any chance of breaking any of the map's invariants? No.
But the fact that the element exists, in the map, is part of the
maps internal state. You can't change this via the reference,
but you can certainly change it via other functions, while the
reference is still present. E.g.:
std::map< int, int > theMap ;
int& r = theMap[ 5 ] ;
theMap.erase( 5 ) ;
// ...
The presence or absense of the element in the map *is* part of
the map's internal state. And a reference to the element is
thus also part of the map's internal state, since it designates
something under control of the map.
Note, that the map class doesn't return a non-const reference
from the "size()" member-function. It could return either by
value or by const reference, either would be safe (assuming
appropriate internal changes,) and switching back in forth
between them would not affect code that uses map::size() in
the slightest. (If it *did* affect code that uses the
member-function, the it is the calling code that is messed
up.)
[What] if the client takes the address of [a const-reference]
return, and later uses it.
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'.
}
That's more or less it. A more typical example might be a map
of external identifiers to entity objects. Somewhere, you need
a function which looks up the object, and returns a pointer to
it. And you don't want to call that function every single
access to the object.
I suppose that one could argue that the "internal state" of the
map here is only the pointer, and not the entity object itself,
because what the std::map will hold will be a pointer, but that
really doesn't change anything at the conceptual level. At the
conceptual level, the "internal state" of the map is your data
base, and you certainly do want functions which return pointers
to that.
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.
So you're saying that if I have a set of entity objects, I
should be required to do lookup in every expression which
accesses one of the objects. Internally, of course, it would be
an std::set< MyType* > (since MyType isn't copiable). But the
comparison function would dereference the pointer, so the values
in MyType would definitely be involved in the class invariants
of std::set.
--
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