In the following line of code:
bootrec_reset(File(path, size, off), blksize);
Calling a function with prototype:
static void bootrec_reset(File &file, ssize_t blksize);
I receive this error:
libcpfs/mkfs.cc:99:53: error: invalid initialization of non-const reference of type 'File&' from an rvalue of type 'File'
libcpfs/mkfs.cc:30:13: error: in passing argument 1 of 'void bootrec_reset(File&, ssize_t)'
I'm aware that you can not pass non-const references (const &
) to rvalues according to the standard. MSVC however allows you to do this (see this question). This question attempts to explain why but the answer makes no sense as he is using references to literals, which are a corner case and should obviously be disallowed.
In the given example it's clear to see that following order of events will occur (as it does in MSVC):
File
's constructor will be called.File
, and blksize
, are pushed on the stack.bootrec_reset
makes use of file
.bootrec_reset
, the temporary File
is destroyed.It's necessary to point out that the File
reference needs to be non-const, as it's a temporary handle to a file, on which non-const methods are invoked. Furthermore I don't want to pass the File
's constructor arguments to bootrec_reset
to be constructed there, nor do I see any reason to manually construct and destroy a File
object in the caller.
So my questions are:
An lvalue reference can bind to an lvalue, but not to an rvalue.
C does not support references or passing by reference. You should use pointers instead and pass by address. Pass-by-value is efficient for primitive types, but does a shallow copy for structs. In C++ it makes a LOT of sense to pass objects by reference for efficiency.
No. A reference is simply an alias for an existing object. const is enforced by the compiler; it simply checks that you don't attempt to modify the object through the reference r .
If you could pass an r-value by (non-const) reference, you could also be able to assign to it from inside the function. Therefore the rule that if r-values are to be passed by reference, this has to be a const reference.
Yes, the fact that plain functions cannot bind non-const references to temporaries -- but methods can -- has always bugged me. TTBOMK the rationale goes something like this (sourced from this comp.lang.c++.moderated thread):
Suppose you have:
void inc( long &x ) { ++x; }
void test() {
int y = 0;
inc( y );
std::cout << y;
}
If you allowed the long &x
parameter of inc()
to bind to a temporary long
copy made from y
, this code obviously wouldn't do what you expect -- the compiler would just silently produce code that leaves y
unchanged. Apparently this was a common source of bugs in the early C++ days.
Had I designed C++, my preference would have been to allow non-const references to bind to temporaries, but to forbid automatic conversions from lvalues to temporaries when binding to references. But who knows, that might well have opened up a different can of worms...
Practical experience with the opposite convention, which was how things worked originally. C++ is to a large degree an evolved language, not a designed one. Largely, the rules that are still there are those that turned out to work (although some BIG exceptions to that occurred with the 1998 standardization, e.g. the infamous export
, where the committee invented rather than standardizing existing practice).
For the binding rule one had not only the experience in C++, but also similar experience with other languages such as Fortran.
As @j_random_hacker notes in his answer (which as I wrote this was scored 0, showing that the scoring in SO really doesn't work as a measure of quality), the most serious problems have to do with implicit conversions and overload resolution.
You can't.
Instead of ...
bootrec_reset(File(path, size, off), blksize);
... write ...
File f(path, size, off);
bootrec_reset(f, blksize);
Or define an appropriate overload of bootrec_reset
. Or, if "clever" code appeals, you can in principle write bootrec_reset(tempref(File(path, size, off)), blksize);
, where you simply define tempref
to return its argument reference appropriately const-casted. But even though that's a technical solution, don't.
Nope, nothing that changes things for the given code.
If you're willing to rewrite, however, then you can use e.g. C++0x rvalue references, or the C++98 workarounds shown above.
Cheers & hth.,
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With