Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Question on Myers #30

Reply
Thread Tools

Question on Myers #30

 
 
Ioannis Vranos
Guest
Posts: n/a
 
      02-27-2005
Alf P. Steinbach wrote:
>
> void client( bool thisOrThat )
> {
> std::string const gwb = "Bah!";
> std::string const* ps = thisOrThat? &gwb : &iv.getstring();
>
> std::cout << *ps << std::endl;
> }



Making it more complete:

#include <iostream>

class SomeClass
{
std::string s;

public:
SomeClass():s("Test string") {}

const std::string &getstring() const { return s; }
};

void client( bool thisOrThat )
{
SomeClass iv;

std::string const gwb = "Bah!";
std::string const* ps = thisOrThat? &gwb : &iv.getstring();

std::cout << *ps << std::endl;
}


int main()
{
client(true);
}


Yes, if you convert const std::string & to const std::string you end up
getting the address of a temporary and all my compilers warn of this.


However this is an unusual use at first, to use a pointer to a returned
const string &, and the user as it seems can still take the address of
the temporary even if you return a temporary since the beginning.


If you want to make more obvious that this should not happen, you can
add to the documentation that the const references or const pointers
returned by these methods point to an implementation specific space that
can change after that call.


This is the case of all facilities of <ctime> BTW. All pointers returned
point to implementation-specific areas and can change after the call.



--
Ioannis Vranos

http://www23.brinkster.com/noicys
 
Reply With Quote
 
 
 
 
Ioannis Vranos
Guest
Posts: n/a
 
      02-27-2005
Ioannis Vranos wrote:

> Making it more complete:
>
> #include <iostream>
>
> class SomeClass
> {
> std::string s;
>
> public:
> SomeClass():s("Test string") {}
>
> const std::string &getstring() const { return s; }
> };
>
> void client( bool thisOrThat )
> {
> SomeClass iv;
>
> std::string const gwb = "Bah!";
> std::string const* ps = thisOrThat? &gwb : &iv.getstring();
>
> std::cout << *ps << std::endl;
> }
>
>
> int main()
> {
> client(true);
> }
>
>
> Yes, if you convert const std::string & to const std::string you end up
> getting the address of a temporary and all my compilers warn of this.
>
>
> However this is an unusual use at first, to use a pointer to a returned
> const string &, and the user as it seems can still take the address of
> the temporary even if you return a temporary since the beginning.
>
>
> If you want to make more obvious that this should not happen, you can
> add to the documentation that the const references or const pointers
> returned by these methods point to an implementation specific space that
> can change after that call.
>
>
> This is the case of all facilities of <ctime> BTW. All pointers returned
> point to implementation-specific areas and can change after the call.



A reference:

http://www.research.att.com/~bs/3rd_loc.pdf


Check on page 906:

"Beware: both localtime() and gmtime() return a tm * to a statically
allocated object; a subsequent call of that function will change the
value of that object. Either use such a return value immediately,
or copy the tm into storage that you control.

Similarly, asctime() returns a pointer to a statically allocated
character array."



--
Ioannis Vranos

http://www23.brinkster.com/noicys
 
Reply With Quote
 
 
 
 
Howard
Guest
Posts: n/a
 
      02-28-2005

"Master of C++" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) oups.com...
> Hi,
>
> In Effective C++, #30, Myers says:
>
> "Avoid member functions that return pointers or references to members
> less accessible than themselves"
>
> But, operator[] does exactly the opposite. Is overloading operator[]
> considered "evil" in C++ circles ? I write a lot of numerical
> programming code, and such operators make life easier for me.
>
> Thanks,
> Vijay.
>


Perhaps you have an earlier edition? The 2nd edition of that book states
very clearly

"Item 30: Avoid member functions that return non-const pointers or
references to members less accesiable than themselves."

Notice the "non-const" part of that heading. That's the key to his whole
argument. He's saying that, if you return a non-const reference, then
you're in effect granting permission for the caller to modify member data
that you've already said they have no business touching. It's ok to return
a const reference, since then the data is not modifiable by the caller.
Similar arguments are made regarding pointers, with added details about
calling member functions with less visibility.

-Howard




 
Reply With Quote
 
Jonathan Turkanis
Guest
Posts: n/a
 
      02-28-2005
Howard wrote:

> Notice the "non-const" part of that heading. That's the key to his
> whole argument. He's saying that, if you return a non-const
> reference, then you're in effect granting permission for the caller
> to modify member data that you've already said they have no business
> touching.


The problem with this argument is that declaring a data member private by itself
does not mean that the client has no business "touching it." By providing a
function which returns a non-const reference to (part of) such a data member,
you can give the client an approved way to "touch" it. Forcing the client to use
an accessor function can still provide a degree of encapsulation; e.g. only part
of a data member can be exposed and the data can be relocated or renamed without
affecting the public interface.

Jonathan


 
Reply With Quote
 
Howard
Guest
Posts: n/a
 
      02-28-2005

"Jonathan Turkanis" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> Howard wrote:
>
>> Notice the "non-const" part of that heading. That's the key to his
>> whole argument. He's saying that, if you return a non-const
>> reference, then you're in effect granting permission for the caller
>> to modify member data that you've already said they have no business
>> touching.

>
> The problem with this argument is that declaring a data member private by
> itself
> does not mean that the client has no business "touching it." By providing
> a
> function which returns a non-const reference to (part of) such a data
> member,
> you can give the client an approved way to "touch" it. Forcing the client
> to use
> an accessor function can still provide a degree of encapsulation; e.g.
> only part
> of a data member can be exposed and the data can be relocated or renamed
> without
> affecting the public interface.
>
> Jonathan
>
>


I'm not sure I understand if you're agreeing or disagreeing with what I've
said (or with what Mr. Meyers has written). Have you read the text I'm
referring to? The use of an accessor function is exactly what he shows. He
just says that it should not return a non-const reference or pointer to the
data. Obviously there are many things to consider when designing a class,
but the point of this *particular* reference is to not make such an accessor
function return a *non-const* reference, because returning a non-const
reference essentially allows the user direct access to the underlying data,
as if you had made the variable public in the first place.

-Howard


 
Reply With Quote
 
Alf P. Steinbach
Guest
Posts: n/a
 
      02-28-2005
* Howard:
>
> "Jonathan Turkanis" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...
> > Howard wrote:
> >
> >> Notice the "non-const" part of that heading. That's the key to his
> >> whole argument. He's saying that, if you return a non-const
> >> reference, then you're in effect granting permission for the caller
> >> to modify member data that you've already said they have no business
> >> touching.

> >
> > The problem with this argument is that declaring a data member private by
> > itself
> > does not mean that the client has no business "touching it." By providing
> > a
> > function which returns a non-const reference to (part of) such a data
> > member,
> > you can give the client an approved way to "touch" it. Forcing the client
> > to use
> > an accessor function can still provide a degree of encapsulation; e.g.
> > only part
> > of a data member can be exposed and the data can be relocated or renamed
> > without
> > affecting the public interface.
> >
> > Jonathan
> >
> >

>
> I'm not sure I understand if you're agreeing or disagreeing with what I've
> said (or with what Mr. Meyers has written). Have you read the text I'm
> referring to? The use of an accessor function is exactly what he shows. He
> just says that it should not return a non-const reference or pointer to the
> data. Obviously there are many things to consider when designing a class,
> but the point of this *particular* reference is to not make such an accessor
> function return a *non-const* reference, because returning a non-const
> reference essentially allows the user direct access to the underlying data,
> as if you had made the variable public in the first place.


The 'at' member function of the standard containers is one counter-example.

As I wrote earlier, "Effective C++" are rules of thumbs.

This one is not a particularly good one.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
Howard
Guest
Posts: n/a
 
      02-28-2005

"Alf P. Steinbach" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
>* Howard:
>>
>> "Jonathan Turkanis" <(E-Mail Removed)> wrote in message
>> news:(E-Mail Removed)...
>> > Howard wrote:
>> >
>> >> Notice the "non-const" part of that heading. That's the key to his
>> >> whole argument. He's saying that, if you return a non-const
>> >> reference, then you're in effect granting permission for the caller
>> >> to modify member data that you've already said they have no business
>> >> touching.
>> >
>> > The problem with this argument is that declaring a data member private
>> > by
>> > itself
>> > does not mean that the client has no business "touching it." By
>> > providing
>> > a
>> > function which returns a non-const reference to (part of) such a data
>> > member,
>> > you can give the client an approved way to "touch" it. Forcing the
>> > client
>> > to use
>> > an accessor function can still provide a degree of encapsulation; e.g.
>> > only part
>> > of a data member can be exposed and the data can be relocated or
>> > renamed
>> > without
>> > affecting the public interface.
>> >
>> > Jonathan
>> >
>> >

>>
>> I'm not sure I understand if you're agreeing or disagreeing with what
>> I've
>> said (or with what Mr. Meyers has written). Have you read the text I'm
>> referring to? The use of an accessor function is exactly what he shows.
>> He
>> just says that it should not return a non-const reference or pointer to
>> the
>> data. Obviously there are many things to consider when designing a
>> class,
>> but the point of this *particular* reference is to not make such an
>> accessor
>> function return a *non-const* reference, because returning a non-const
>> reference essentially allows the user direct access to the underlying
>> data,
>> as if you had made the variable public in the first place.

>
> The 'at' member function of the standard containers is one
> counter-example.
>
> As I wrote earlier, "Effective C++" are rules of thumbs.


I agree, absolutely!

>
> This one is not a particularly good one.
>


Again, I fail to see what the disagreement is (or what's not particularly
good about his advice here, to put it another way).

Here is a response I see from you in this thread:

<paste>
Ioannis: If you were returning a non-const reference(!) to your internal
data member, then you shouldn't do it.

Alf: Right.
</paste>

What I see Mr. Meyers saying is *exactly* what I see you agreeing to above:
that you shouldn't return a non-const reference to an internal data member.
Did I miss something?

-Howard





 
Reply With Quote
 
Jonathan Turkanis
Guest
Posts: n/a
 
      02-28-2005
Howard wrote:
> "Jonathan Turkanis" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...
>> Howard wrote:
>>
>>> Notice the "non-const" part of that heading. That's the key to his
>>> whole argument. He's saying that, if you return a non-const
>>> reference, then you're in effect granting permission for the caller
>>> to modify member data that you've already said they have no business
>>> touching.

>>
>> The problem with this argument is that declaring a data member
>> private by itself
>> does not mean that the client has no business "touching it." By
>> providing a
>> function which returns a non-const reference to (part of) such a data
>> member,
>> you can give the client an approved way to "touch" it. Forcing the
>> client to use
>> an accessor function can still provide a degree of encapsulation;
>> e.g. only part
>> of a data member can be exposed and the data can be relocated or
>> renamed without
>> affecting the public interface.
>>
>> Jonathan
>>
>>

>
> I'm not sure I understand if you're agreeing or disagreeing with what
> I've said


disagreeing

(or with what Mr. Meyers has written).

disagreeing

> Have you read the
> text I'm referring to?


Yes.

> The use of an accessor function is exactly
> what he shows. He just says that it should not return a non-const
> reference or pointer to the data. Obviously there are many things to
> consider when designing a class, but the point of this *particular*
> reference is to not make such an accessor function return a
> *non-const* reference, because returning a non-const reference
> essentially allows the user direct access to the underlying data, as
> if you had made the variable public in the first place.


In my original message I was trying to show that this argument is fallacious.

Providing a public accessor function returning a non-const reference is not the
same as making the member data public. Eg.:

class Thing {
public:
...
int& size() { return size_; }
const int& size() const { return size_; }
int& weight() { return weight_; }
const int& weight() const { return weight_; }
private:
...
int size_;
int weight_;
};

can be reimplemented

class Thing {
public:
....
int& size() { return size_weight_.first; }
const int& size() const { return size_weight_.first; }
int& weight() { return size_weight_.second; }
const int& weight() const { return size_weight_.second; }
private:
...
std:air<int, int> size_weight_;
};

without changing the public interface of Thing. This would not be possible if
size had been exposed as a public data member of type int. This is one of the
traditional advantages of using accessor functions, and it is not diminished by
the fact that two of them return non-const references.

> -Howard


Jonathan


 
Reply With Quote
 
Howard
Guest
Posts: n/a
 
      02-28-2005

"Jonathan Turkanis" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> Howard wrote:
>> "Jonathan Turkanis" <(E-Mail Removed)> wrote in message
>> news:(E-Mail Removed)...
>>> Howard wrote:
>>>
>>>> Notice the "non-const" part of that heading. That's the key to his
>>>> whole argument. He's saying that, if you return a non-const
>>>> reference, then you're in effect granting permission for the caller
>>>> to modify member data that you've already said they have no business
>>>> touching.
>>>
>>> The problem with this argument is that declaring a data member
>>> private by itself
>>> does not mean that the client has no business "touching it." By
>>> providing a
>>> function which returns a non-const reference to (part of) such a data
>>> member,
>>> you can give the client an approved way to "touch" it. Forcing the
>>> client to use
>>> an accessor function can still provide a degree of encapsulation;
>>> e.g. only part
>>> of a data member can be exposed and the data can be relocated or
>>> renamed without
>>> affecting the public interface.
>>>
>>> Jonathan
>>>
>>>

>>
>> I'm not sure I understand if you're agreeing or disagreeing with what
>> I've said

>
> disagreeing
>
> (or with what Mr. Meyers has written).
>
> disagreeing
>
>> Have you read the
>> text I'm referring to?

>
> Yes.
>
>> The use of an accessor function is exactly
>> what he shows. He just says that it should not return a non-const
>> reference or pointer to the data. Obviously there are many things to
>> consider when designing a class, but the point of this *particular*
>> reference is to not make such an accessor function return a
>> *non-const* reference, because returning a non-const reference
>> essentially allows the user direct access to the underlying data, as
>> if you had made the variable public in the first place.

>
> In my original message I was trying to show that this argument is
> fallacious.
>
> Providing a public accessor function returning a non-const reference is
> not the
> same as making the member data public. Eg.:
>
> class Thing {
> public:
> ...
> int& size() { return size_; }
> const int& size() const { return size_; }
> int& weight() { return weight_; }
> const int& weight() const { return weight_; }
> private:
> ...
> int size_;
> int weight_;
> };
>
> can be reimplemented
>
> class Thing {
> public:
> ....
> int& size() { return size_weight_.first; }
> const int& size() const { return size_weight_.first; }
> int& weight() { return size_weight_.second; }
> const int& weight() const { return size_weight_.second; }
> private:
> ...
> std:air<int, int> size_weight_;
> };
>
> without changing the public interface of Thing. This would not be possible
> if
> size had been exposed as a public data member of type int. This is one of
> the
> traditional advantages of using accessor functions, and it is not
> diminished by
> the fact that two of them return non-const references.
>
>> -Howard

>
> Jonathan
>
>


But that's not his point! What he discusses is this:

class Y
{
public:
int y;
};

class X
{
Y yx; // This should be private!
public:
Y& gety() { return yx; }
};

int main()
{
X xmain;
Y& ymain = xmain.gety();
ymain.y = 3; // But now you're changing the contents of the *private*
member yx!
}

The non-const reference returned from get() allows the main function to
modify the contents of the private member of xmain.

Mr. Meyers is saying that, in effect, yx is no longer really private,
because it can be accessed by getting a non-const reference to it.
Returning a const reference instead, that would not happen.

-Howard


 
Reply With Quote
 
E. Mark Ping
Guest
Posts: n/a
 
      03-01-2005
In article <(E-Mail Removed)>,
Alf P. Steinbach <(E-Mail Removed)> wrote:
>The 'at' member function of the standard containers is one counter-example.
>
>As I wrote earlier, "Effective C++" are rules of thumbs.
>
>This one is not a particularly good one.


This is a particulary foolish example. Containers present an
interface to the contained data. vector::at and vector:perator[]
dont' return non-const references to their *implementation* but to the
contained data, which is the purpose of the continer.

If (say) std::vector::capacity() returned a reference to the allocated
capacity, *that* would be a problem.
--
Mark Ping
http://www.velocityreviews.com/forums/(E-Mail Removed)
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
The Kanye West show was Mike Myers SECOND awkward live tv moment heinzmenses@hotmail.com Digital Photography 31 09-12-2005 08:54 PM
Michael Myers A+ 5th edition question Fred Mathering A+ Certification 4 05-27-2004 04:46 AM
Mike Myers 70-293 Book Brian MCSA 2 08-04-2003 01:10 PM
Mike Myers Book? steven A+ Certification 2 08-04-2003 02:02 AM
Re: A+!! Thanks M. Myers techophile A+ Certification 1 06-24-2003 07:43 PM



Advertisments