Re: Initializing member references to dummy member variables
On Monday, 12 August 2013 15:51:11 UTC+1, K. Frank wrote:
First off, let me thank Luca for directing me to
boost::optional / std::optional. That looks like
the semantics I am looking for.
Let me answer several questions by several respondents
in this one post, below.
On Monday, August 12, 2013 7:35:01 AM UTC-4, James Kanze wrote:
On Monday, 12 August 2013 04:29:56 UTC+1, K. Frank wrote:
Suppose I have a class that has a member reference
variable, and sometimes I want to initialize it,
and sometimes I don't.
...
As a concrete example, let's say I have a class that
is constructed with a value of or reference to some kind
of handle, but the handle might be a number or it might
be a string:
struct Handle {
Handle (int iHandle) :
iHandle_(iHandle),
sHandle_(dummy),
useIHandle_(true)
{}
Handle (const std::string& sHandle) :
iHandle_(0),
sHandle_(sHandle),
useIHandle_(false)
{}
const int iHandle_;
const std::string& sHandle_;
bool useIHandle_;
std::string dummy_;
}
The point is that the member reference variable sHandle_
is supposed to be initialized (in the constructors'
initialization lists), whether or not it's actually
going to be used. The constructor that takes an int
argument doesn't have any std::strings floating
around with which to initialize sHandle_, hence the
introduction of the member variable dummy_.
...
Answers to questions raised in previous posts:
Use boost::optional or wait for std::optional :
Indeed. This looks like the best answer, given
the specific question I asked.
It's interesting to note that the c++14 proposal
for std::optional leaves open whether optional
references should be supported:
http://isocpp.org/files/papers/N3672.html#optional_ref
Probably because it already exists. An "optional" reference is
called a pointer. (Except that a pointer is more efficient, and
less complicated.)
What is the reason for making sHandle_ a const reference
instead of a member variable?
In that case you wouldn't need the dummy_ member:
There are a couple of possible reasons. (Again, this
is just an example.)
One is to stick with style that says to pass class
objects by const reference rather than value. (A
style that I believe James promotes.)
I've not so much promoted it, as simply pointed out that it is
ubiquitous, to the point where anything else causes the reader
to ask questions. But the issue here isn't "passing" the value;
I have no problems with the parameter to the constructor being
a const reference. The issue is a member, in an object which
might outlive the object referred to by the constructor.
If the value being passed in were bulkier than a
(short) string, passing by (const) reference could
be significantly cheaper. (But if the default value
of the class were comparably bulky, the use of the
dummy variable could vitiate any savings.)
And (in the analogous non-const case) one would
want a reference if the original passed-in argument
were to be modified.
*IF* the semantics of the class are to modify something else,
then using a reference or a pointer in the class is necessary.
In general, however, it's something to avoid.
If you use a pointer instead of a reference, you can set it
to NULL initially, and then to something else, later, if the
opportunity arises. You cannot reassign the reference to
something else, later. My opinion is that if you are using a
reference, it should always be initialized with a useful
rvalue.
Yes, using a pointer, with the possibility of initializing
it to a nullptr value, seems very reasonable and natural.
Are there any reasons to prefer boost/std::optional over
the tried-and-true pointer approach? Are there any benefits
(if only syntactic sugar) to the caller of the constructor?
No.
I've had my own Fallible class since long before
boost::optional. Practically speaking, it is useful for
returning values which can fail, or (as a mutable member) for
cached values. Or in very rare cases, as a parameter, since it
doesn't require an lvalue (as a pointer would). I've never
really used it as an optional value, however.
Why is the variable a reference? The class std::string
represents values, and in most cases, should be a value, and not
a reference. For starters, references can dangle.
Ach, James, you of all people! Just the other day you
were expounding upon the virtues of passing strings by
const reference:
Speed of passing a string by value vs. const reference
https://groups.google.com/forum/#!topic/comp.lang.c++/0UuKuYp0fqY
Kidding aside, obviously for a (short) string, passing
by value would work just fine and would avoid the
uninitialized reference issue. But in use cases where
the object being passed in was too expensive to copy or
needed to be modified, pass-by-value wouldn't be appropriate.
Pass by reference has nothing to do with member reference.
Something passed by const reference will be used in the
function, or a copy will be made, so there can be no issues
involving dangling references (usually---one can easily
construct cases where there could be a problem, but they tend
not to occur naturally).
Consider for a moment the state your object will be left in if
I do:
Handle* h = new Handle( "lable" );
It seems to me that for the use case I have in mind,
using a pointer or an optional would be the way to go.
A pointer will have the same problems as a reference (except
that it won't render the class unassignable). It can dangle.
Optional is probably extra overhead here (not to mention that
boost::optional has a very poor interface). Just use a value,
with the empty string if it isn't being used. (If you need an
extra variable to specify which type is active, it should be
a separate enum type, and not bound to the string variable, when
it is equally relevant to the int.)
Leaving aside the fact that optional is not yet standard,
is there any reason to prefer one over the other?
Maybe using the old-fashioned pointer solution is the
cleanest way to go here.
If you like dangling pointers.
--
James