K. Frank
6/13/2016 8:42:00 PM
Hello Öö!
On Monday, June 13, 2016 at 1:30:45 PM UTC-4, Öö Tiib wrote:
> On Monday, 13 June 2016 16:40:56 UTC+3, K. Frank wrote:
> > Hi Ian!
> >
> > On Sunday, June 12, 2016 at 3:57:15 PM UTC-4, Ian Collins wrote:
> > > On 06/13/16 07:47 AM, James Moe wrote:
> > > > ...
> > > > pmmsend.c:449:63: error: invalid initialization of reference of type
> > > > 'std::string& {aka std::basic_string<char>&}' from expression of type
> > > > 'char*'
> > > > ...
> > Just to be sure I understand:
> >
> > The language could have permitted passing a temporary as
> > a non-cost reference, f (std::string &str);, but most of
> > the time you would be making a mistake doing this, so the
> > language prohibits it.
> ...
> > That is, the code generated when binding a temporary
> > to a non-cost rvalue reference is the same as what
> > one would have expected (okay, what I would have expected)
> > if binding to a non-cost lvalue reference has been
> > allowed.
>
> It is hard to know what you would had expected.
Here's a not-too-badly-contrived example to illustrate
what I would have expected:
void translateInPlaceAndPrint (std::string &str) {
if (str == "Good Morning!") str == "Guten Morgan!";
std::cout << str << std::endl;
}
// use case 1 -- won't compile
translateInPlaceAndPrint ("Good Morning!");
// use case 1 -- work-around
std::string tmp = "Good morning!";
translateInPlaceAndPrint (tmp);
// use case 2
std::string useMoreThanOnce = "Good Morning!";
translateInPlaceAndPrint (useMoreThanOnce);
// print again just for fun
std::cout << useMoreThanOnce << std::endl;
If "// use case 1 -- won't compile" were permitted, what
I would expect would be:
1) A temporary std::string is constructed on the stack
from "Good Morning!"
2) The temporary is bound to the non-const reference
argument
3) The lifetime of the temporary is extended to when
the function call returns
4) The function modifies its (non-const reference)
argument in place (and prints it out)
5) The function returns, the temporary's extended
lifetime ends, and the temporary is destroyed
This seems quite reasonable, and seems to me to be what
most people would expect if this were actually permitted.
It's certainly not necessary to permit this -- the
work-around is easy and obvious. (And the work-around
is almost the same as my hypothetical "expected"
behavior. The only difference is that the lifetime
of tmp is to the end of its block scope, rather than
just to when the function returns.)
> ...
> > Is this correct, or am I missing something important
> > about this specific use case?
>
> Programming languages are meant for describing behavior of
> programs and are not for instructing processors. That is the
> sole little step we have ever taken above assemblers.
Well, yes. And it is true that forbidding the binding of
temporaries to non-const references does prevent a certain
class of errors.
But the design of c++ has generally been to be
self-consistently flexible, rather than preventing you
from shooting yourself in the foot.
It just seems to me that permitting the binding of a
temporary to non-cost reference would be very much in
the spirit of c++, and would work just fine if implemented
as I described above, unless there is some other set
of problems I've overlooked.
I'm not proposing that the language permit this. I'm
just asking whether the language could have easily
permitted this (for example, as outlined above), or
whether I'm missing something and trying to permit this
would generate a whole other set of complications that
I've overlooked.
Thanks for any further enlightenment.
K. Frank