 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
JKop Guest
|
Posted: Thu Jun 24, 2004 10:26 am Post subject: Read-only, as opposed to const member |
|
|
Back when I read my first C++ book, I was given the following scenario:
class Cheese
{
public:
int number_of_holes;
int colour;
};
The thing is, you want the "user" of this class to be able to read from the
two above variables, but no be able to change them. The book retardly gave
the following:
class Cheese
{
private:
int number_of_holes;
int colour;
public:
int GetNumberOfHoles(void);
int GetColour(void);
};
What do yous think of the following:
class Cheese
{
private:
int number_of_holes;
int colour;
public:
const int& GetNumberOfHoles(void)
{
return number_of_holes;
}
const int& GetColour(void)
{
return colour;
}
};
int main(void)
{
Cheese chalk;
chalk.GetNumberOfHoles();
}
I wonder was so many books think they have to show you the stupid way before
they give you the lean, mean, efficient way.
-JKop
|
|
| Back to top |
|
 |
JKop Guest
|
Posted: Thu Jun 24, 2004 11:19 am Post subject: Re: Read-only, as opposed to const member |
|
|
An even better idea!:
class Cheese
{
private:
int prv_number_of_holes;
int prv_colour;
public:
const int& number_of_holes;
const int& colour;
Cheese(void) : number_of_holes(prv_number_of_holes),
colour(prv_colour)
{
;
}
void Blah(void)
{
prv_number_of_holes = 52;
prv_colour = 2;
}
};
int main(void)
{
Cheese chalk;
TakesInt(chalk.number_of_holes);
chalk.number_of_holes = 52; //Compile error
}
This way, the actual class member functions and also friend functions have
write-access to these member variables, while the "user" only has read-only
access!
-JKop
|
|
| Back to top |
|
 |
Richard Herring Guest
|
Posted: Thu Jun 24, 2004 11:23 am Post subject: Re: Read-only, as opposed to const member |
|
|
In message <z%xCc.3043$Z14.3785 (AT) news (DOT) indigo.ie>, JKop <NULL (AT) NULL (DOT) NULL>
writes
| Quote: | Back when I read my first C++ book, I was given the following scenario:
class Cheese
{
public:
int number_of_holes;
int colour;
};
The thing is, you want the "user" of this class to be able to read from the
two above variables, but no be able to change them. The book retardly gave
the following:
class Cheese
{
private:
int number_of_holes;
int colour;
public:
int GetNumberOfHoles(void);
int GetColour(void);
|
Both of those should be const functions, and the "void" is unidiomatic.
| Quote: | };
What do yous think of the following:
class Cheese
{
private:
int number_of_holes;
int colour;
public:
const int& GetNumberOfHoles(void)
{
return number_of_holes;
}
const int& GetColour(void)
{
return colour;
}
|
I think those should be const functions, too, and you don't need the
"void".
| Quote: | };
int main(void)
{
Cheese chalk;
chalk.GetNumberOfHoles();
|
Pointless. Didn't you mean
something = chalk.GetNumberOfHoles();
? There's an important difference.
| Quote: | }
I wonder was so many books think they have to show you the stupid way before
they give you the lean, mean, efficient way.
|
Because it's the safe way? Once you start returning references, the
next thing is to try returning references to temporaries, with hilarious
consequences.
What do you think you would gain by returning a reference?
I doubt that returning an int by value is likely to be any more obese or
less efficient than returning a const reference. Even if you'd
substituted some class with a costly copy constructor, don't forget that
ultimately you want to _do_ something with the value of whatever the
function returns, or why call it in the first place? And that means
that somewhere or other there's likely to be a copy operation anyway,
whether you return a value or a reference. Given the existence of return
value optimisation, the difference in cost may be less than you
expected.
--
Richard Herring
|
|
| Back to top |
|
 |
Karl Heinz Buchegger Guest
|
Posted: Thu Jun 24, 2004 11:24 am Post subject: Re: Read-only, as opposed to const member |
|
|
JKop wrote:
| Quote: |
What do yous think of the following:
class Cheese
{
private:
int number_of_holes;
int colour;
public:
const int& GetNumberOfHoles(void)
{
return number_of_holes;
}
const int& GetColour(void)
{
return colour;
}
};
int main(void)
{
Cheese chalk;
chalk.GetNumberOfHoles();
}
I wonder was so many books think they have to show you the stupid way before
they give you the lean, mean, efficient way.
|
On most typical machines this is no more efficient then returning
the values directly. There is literally no point in replacing
a pass by value with a pass per reference for builtin types
like int, double, char, etc...
--
Karl Heinz Buchegger
[email]kbuchegg (AT) gascad (DOT) at[/email]
|
|
| Back to top |
|
 |
Karl Heinz Buchegger Guest
|
Posted: Thu Jun 24, 2004 11:39 am Post subject: Re: Read-only, as opposed to const member |
|
|
JKop wrote:
| Quote: |
An even better idea!:
class Cheese
{
private:
int prv_number_of_holes;
int prv_colour;
public:
const int& number_of_holes;
const int& colour;
Cheese(void) : number_of_holes(prv_number_of_holes),
colour(prv_colour)
{
;
}
void Blah(void)
{
prv_number_of_holes = 52;
prv_colour = 2;
}
};
int main(void)
{
Cheese chalk;
TakesInt(chalk.number_of_holes);
chalk.number_of_holes = 52; //Compile error
}
This way, the actual class member functions and also friend functions have
write-access to these member variables, while the "user" only has read-only
access!
|
and when the internals of that class Cheese change, all the code that uses
that class breaks immediatly. Congratulations: you just found a clever way
of breaking the concept of encapsulation :-)
Trust your compilers optimizer!
He may do more then you expect.
--
Karl Heinz Buchegger
[email]kbuchegg (AT) gascad (DOT) at[/email]
|
|
| Back to top |
|
 |
Peter van Merkerk Guest
|
Posted: Thu Jun 24, 2004 12:24 pm Post subject: Re: Read-only, as opposed to const member |
|
|
JKop wrote:
| Quote: | Back when I read my first C++ book, I was given the following scenario:
class Cheese
{
public:
int number_of_holes;
int colour;
};
The thing is, you want the "user" of this class to be able to read from the
two above variables, but no be able to change them. The book retardly gave
the following:
class Cheese
{
private:
int number_of_holes;
int colour;
public:
int GetNumberOfHoles(void);
int GetColour(void);
};
What do yous think of the following:
class Cheese
{
private:
int number_of_holes;
int colour;
public:
const int& GetNumberOfHoles(void)
{
return number_of_holes;
}
const int& GetColour(void)
{
return colour;
}
};
int main(void)
{
Cheese chalk;
chalk.GetNumberOfHoles();
}
I wonder was so many books think they have to show you the stupid way before
they give you the lean, mean, efficient way.
|
If those funtions are inlined and if you use an optimizing compiler it
will most likely not make a difference whether you return by reference
or return by value. In trivial cases like this example the contents of
the main() function would most likely be completely optimized away
(since everything is inline in this example the compiler can determine
that there are no observable side effects). In cases where the main()
function uses the return values (so the calls to the chalk object can
not be optimized away), the compiler will most likely generate exactly
the same code for both cases.
Note that the optimization story changes when the member functions of
the Cheese class are not inlined (i.e. when the implementation of these
member functions are in a different translation unit). In this case the
compiler does not know what happens inside the member functions, and
therefore the optimizer must be conservative and must call the functions.
For simple types (like int), that have zero construction and destruction
overhead and have very low copy overhead (about the same as copying
pointers which typically happens when dealing with references), there is
most likely no performance gain by using references. In fact in some
cases returning by reference instead of returning by value can even be
slower (taking a peek at assembly code generated by the compiler can be
very instructive). Of course if you have objects that are costly to
copy(construct) using references can give significant performance
benefits, and should be used whenever appropriate.
The reason why books start with the return by value example probably for
educational reasons; start simple first and discuss the more advanced
topics later. Also note that performance is only one of the lofty goals
to pursue. The net effect of the micro optimizations you are after is
usually quite small or even immeasurable. In my experience you are lucky
if you can improve performance that way by more than 20% (there are
exceptions but those are rare). On the other hand it is not rare for
high-level optimizations (e.g. better algorithms) to improve performance
by more than an order of magnitude. You have to consider carefully on
what you spend time. That being said there is obviously no point in
writing needlessly inefficient code.
--
Peter van Merkerk
peter.van.merkerk(at)dse.nl
|
|
| Back to top |
|
 |
tom_usenet Guest
|
Posted: Thu Jun 24, 2004 12:50 pm Post subject: Re: Read-only, as opposed to const member |
|
|
On Thu, 24 Jun 2004 10:26:39 GMT, JKop <NULL (AT) NULL (DOT) NULL> wrote:
| Quote: | Back when I read my first C++ book, I was given the following scenario:
class Cheese
{
public:
int number_of_holes;
int colour;
};
The thing is, you want the "user" of this class to be able to read from the
two above variables, but no be able to change them. The book retardly gave
the following:
class Cheese
{
private:
int number_of_holes;
int colour;
public:
int GetNumberOfHoles(void);
int GetColour(void);
};
|
Yes, they miss the const qualification on the member functions, which
is a bad idea.
| Quote: | What do yous think of the following:
class Cheese
{
private:
int number_of_holes;
int colour;
public:
const int& GetNumberOfHoles(void)
{
return number_of_holes;
}
const int& GetColour(void)
{
return colour;
}
};
|
It also misses the const qualification. What's more, the return by
reference exposes the implementation of Cheese, since the class needs
int member variables to return references to. What if you decide to
store the colour as a class internally? You don't want to have to
change the interface.
In addition, returning built-ins by reference is usually a
pessimization - it is slower than return by value, at least until the
optimizer turns it back into return by value!
| Quote: | int main(void)
{
Cheese chalk;
chalk.GetNumberOfHoles();
}
I wonder was so many books think they have to show you the stupid way before
they give you the lean, mean, efficient way.
|
Neither way is good, but yours is actually more stupid.
Tom
--
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
|
|
| Back to top |
|
 |
JKop Guest
|
Posted: Thu Jun 24, 2004 1:27 pm Post subject: Re: Read-only, as opposed to const member |
|
|
Peter van Merkerk posted:
| Quote: | You have to consider carefully on what you spend time. That being said
there is obviously no point in writing needlessly inefficient code.
|
I have all the time in the world! Ahh... the joys of unemployment.
-JKop
|
|
| Back to top |
|
 |
JKop Guest
|
Posted: Thu Jun 24, 2004 1:35 pm Post subject: Re: Read-only, as opposed to const member |
|
|
Richard Herring posted:
| Quote: | In message <z%xCc.3043$Z14.3785 (AT) news (DOT) indigo.ie>, JKop
writes
Back when I read my first C++ book, I was given the following scenario:
class Cheese
{
public:
int number_of_holes;
int colour;
};
The thing is, you want the "user" of this class to be able to read from
the two above variables, but no be able to change them. The book
retardly gave the following:
class Cheese
{
private:
int number_of_holes;
int colour;
public:
int GetNumberOfHoles(void);
int GetColour(void);
Both of those should be const functions, and the "void" is unidiomatic.
|
int GetNumberOfHoles(void) const;
int GetColour(void) const;
"unidiomatic" is a subjective term.
| Quote: | };
What do yous think of the following:
class Cheese
{
private:
int number_of_holes;
int colour;
public:
const int& GetNumberOfHoles(void)
{
return number_of_holes; }
const int& GetColour(void)
{
return colour; }
I think those should be const functions, too, and you don't need the
"void".
|
const int& GetNumberOfHoles(void) const;
const int& GetColour(void) const;
I am fully aware that I don't need the "void".
| Quote: |
};
int main(void)
{
Cheese chalk;
chalk.GetNumberOfHoles();
Pointless. Didn't you mean
something = chalk.GetNumberOfHoles();
|
No.
I didn't suggest there was a point.
| Quote: |
? There's an important difference.
}
I wonder was so many books think they have to show you the stupid way
before they give you the lean, mean, efficient way.
Because it's the safe way? Once you start returning references, the
next thing is to try returning references to temporaries, with
hilarious consequences.
|
Hence the absence of the returning of references to temporaries.
| Quote: | What do you think you would gain by returning a reference?
I doubt that returning an int by value is likely to be any more obese
or less efficient than returning a const reference. Even if you'd
substituted some class with a costly copy constructor, don't forget
that ultimately you want to _do_ something with the value of whatever
the function returns, or why call it in the first place? And that
means that somewhere or other there's likely to be a copy operation
anyway, whether you return a value or a reference. Given the existence
of return value optimisation, the difference in cost may be less than
you expected.
|
If I'm pedantic about it, there's greater probability of the reference form
being more efficent than the return-by-value form, as the return-by-value
form, under the duress of the Standard, *may* create a temporary.
-JKop
|
|
| Back to top |
|
 |
JKop Guest
|
Posted: Thu Jun 24, 2004 1:37 pm Post subject: Re: Read-only, as opposed to const member |
|
|
Karl Heinz Buchegger posted:
| Quote: | and when the internals of that class Cheese change, all the code that
uses that class breaks immediatly. Congratulations: you just found a
clever way of breaking the concept of encapsulation :-)
Trust your compilers optimizer!
He may do more then you expect.
|
So long as you have read-only variables/objects, it should be grand.
-JKop
|
|
| Back to top |
|
 |
Richard Herring Guest
|
Posted: Thu Jun 24, 2004 2:23 pm Post subject: Re: Read-only, as opposed to const member |
|
|
In message <AMACc.3061$Z14.3734 (AT) news (DOT) indigo.ie>, JKop <NULL (AT) NULL (DOT) NULL>
writes
| Quote: | Richard Herring posted:
In message <z%xCc.3043$Z14.3785 (AT) news (DOT) indigo.ie>, JKop
writes
Back when I read my first C++ book, I was given the following scenario:
class Cheese
{
public:
int number_of_holes;
int colour;
};
The thing is, you want the "user" of this class to be able to read from
the two above variables, but no be able to change them. The book
retardly gave the following:
class Cheese
{
private:
int number_of_holes;
int colour;
public:
int GetNumberOfHoles(void);
int GetColour(void);
Both of those should be const functions, and the "void" is unidiomatic.
int GetNumberOfHoles(void) const;
int GetColour(void) const;
"unidiomatic" is a subjective term.
|
Of course. That's why I didn't say "wrong". Nevertheless, it's more to
type and marks you as possibly being an unregenerate C programmer.
| Quote: | };
What do yous think of the following:
class Cheese
{
private:
int number_of_holes;
int colour;
public:
const int& GetNumberOfHoles(void)
{
return number_of_holes; }
const int& GetColour(void)
{
return colour; }
I think those should be const functions, too, and you don't need the
"void".
const int& GetNumberOfHoles(void) const;
const int& GetColour(void) const;
I am fully aware that I don't need the "void".
|
Good. Save yourself a few keystrokes.
| Quote: |
};
int main(void)
{
Cheese chalk;
chalk.GetNumberOfHoles();
Pointless. Didn't you mean
something = chalk.GetNumberOfHoles();
No.
I didn't suggest there was a point.
|
I thought you were trying to make one? If you discard the results of the
side-effect-free function call, the whole thing could be as-if'd away to
nothing.
| Quote: | ? There's an important difference.
}
I wonder was so many books think they have to show you the stupid way
before they give you the lean, mean, efficient way.
Because it's the safe way? Once you start returning references, the
next thing is to try returning references to temporaries, with
hilarious consequences.
Hence the absence of the returning of references to temporaries.
|
Well, good for you.
| Quote: |
What do you think you would gain by returning a reference?
I doubt that returning an int by value is likely to be any more obese
or less efficient than returning a const reference. Even if you'd
substituted some class with a costly copy constructor, don't forget
that ultimately you want to _do_ something with the value of whatever
the function returns, or why call it in the first place? And that
means that somewhere or other there's likely to be a copy operation
anyway, whether you return a value or a reference. Given the existence
of return value optimisation, the difference in cost may be less than
you expected.
If I'm pedantic about it, there's greater probability of the reference form
being more efficent than the return-by-value form, as the return-by-value
form, under the duress of the Standard, *may* create a temporary.
|
And it may not (strange meaning of "duress" you have there.) But getting
a value from the reference involves an extra indirection behind the
scenes, so there's a definite inefficiency there.
--
Richard Herring
|
|
| Back to top |
|
 |
DaKoadMunky Guest
|
Posted: Thu Jun 24, 2004 3:27 pm Post subject: Re: Read-only, as opposed to const member |
|
|
For accessors I prefer the return-by-value approach rather than the
return-by-reference approach.
The return-by-reference approach I believe creates an implementation
dependency.
In your case you are returning references to integers. This seems to work out
fine because you have chosen to store integers and thus have integers with
which to initialize your references.
What happens though if you decide you want to modify your class to change how
and/or where your data is stored?
Where then is the integer to initialize your reference going to come from?
If you no longer have an integer with which to initialize a reference are you
going to change the return type of your accessor? Clients might not
appreciate that.
I think returning by value alleviates some of these problems. The underlying
storage mechanism can change at will. So long as the data represented still
conceptually represents an integer than changes to the implementation need not
have great impact.
As an aside, I also prefer the return-by-value for safety reasons. Your
accessor returns a const reference which of course communicates to its caller
that it may not modify the referenced data. That constness though is easily
cast away which can result in modifications that bypass any "set" functions
that might be in place. Returning by value seems to also alleviate the
possibility that your object could somehow be corrupted.
Of course some people say you shouldn't write code that guards against
deliberate misuse...that writers of such code deserve whatever fate befalls
them.
|
|
| Back to top |
|
 |
JKop Guest
|
Posted: Thu Jun 24, 2004 3:41 pm Post subject: Re: Read-only, as opposed to const member |
|
|
DaKoadMunky posted:
| Quote: | For accessors I prefer the return-by-value approach rather than the
return-by-reference approach.
The return-by-reference approach I believe creates an implementation
dependency.
In your case you are returning references to integers. This seems to
work out fine because you have chosen to store integers and thus have
integers with which to initialize your references.
What happens though if you decide you want to modify your class to
change how and/or where your data is stored?
Where then is the integer to initialize your reference going to come
from?
|
I don't understand your logic.
Let's say I change the int to a double .
A) MY CODE: Change the "const int&" to "const double&"
B) YOUR CODE: Change "int GetColour(void)" to "double GetColour(void)".
Karl mentioned something about this too, but I still don't see your
argument.
| Quote: |
If you no longer have an integer with which to initialize a reference
are you going to change the return type of your accessor? Clients
might not appreciate that.
|
To which code do you refer? My first one with member functions that return
const references, or my second one which has public const member references
which are initialized with private non-const variables?
| Quote: | As an aside, I also prefer the return-by-value for safety reasons.
Your accessor returns a const reference which of course communicates to
its caller that it may not modify the referenced data. That constness
though is easily cast away which can result in modifications that
bypass any "set" functions that might be in place. Returning by value
seems to also alleviate the possibility that your object could somehow
be corrupted.
|
This could lead into the realms of whether there should be const in C++ at
all. There's no const in Python, and their official reason is "We're all
consenting adults here!".
-JKop
|
|
| Back to top |
|
 |
JKop Guest
|
Posted: Thu Jun 24, 2004 3:43 pm Post subject: Re: Read-only, as opposed to const member |
|
|
Karl Heinz Buchegger posted:
| Quote: | and when the internals of that class Cheese change, all the code that
uses that class breaks immediatly. Congratulations: you just found a
clever way of breaking the concept of encapsulation
|
I really don't understand this at all. Could you please be more specific?
-JKop
|
|
| Back to top |
|
 |
Richard Herring Guest
|
Posted: Thu Jun 24, 2004 4:05 pm Post subject: Re: Read-only, as opposed to const member |
|
|
In message <qCCCc.3070$Z14.3818 (AT) news (DOT) indigo.ie>, JKop <NULL (AT) NULL (DOT) NULL>
writes
| Quote: | DaKoadMunky posted:
For accessors I prefer the return-by-value approach rather than the
return-by-reference approach.
The return-by-reference approach I believe creates an implementation
dependency.
In your case you are returning references to integers. This seems to
work out fine because you have chosen to store integers and thus have
integers with which to initialize your references.
What happens though if you decide you want to modify your class to
change how and/or where your data is stored?
Where then is the integer to initialize your reference going to come
from?
I don't understand your logic.
Let's say I change the int to a double .
A) MY CODE: Change the "const int&" to "const double&"
B) YOUR CODE: Change "int GetColour(void)" to "double GetColour(void)".
|
No, that's not what he's saying.
At the moment you have
int & GetColour() const { return colour; }
- or -
int GetColour() const { return colour; }
What happens if you move to a more sophisticated colour model? Instead
of storing an int, maybe you need to compute something from the user's
choice, the available palette, the kind of display device etc...
OK, add some functionality to compute it:
private:
int ComputeComplicatedColour(int userColour, palette p, display d)
const;
If returning a value, no problem; just change your access function to
this:
int GetColour() const
{ return ComputeComplicatedColour(colour, palette, device); }
But if you're returning a reference:
int & GetColour() const
{ return reference to what??? }
--
Richard Herring
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|