[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [lmi] Local variable of rvalue reference type
From: |
Vadim Zeitlin |
Subject: |
Re: [lmi] Local variable of rvalue reference type |
Date: |
Fri, 18 Jan 2019 00:48:08 +0100 |
On Thu, 17 Jan 2019 23:10:46 +0000 Greg Chicares <address@hidden> wrote:
GC> On 2019-01-17 02:33, Vadim Zeitlin wrote:
GC> > On Thu, 17 Jan 2019 01:35:30 +0000 Greg Chicares <address@hidden> wrote:
GC> [...]
GC> > GC> It crossed my mind to try move semantics instead, but at the time I
GC> > GC> avoided doing so because of your review comment on PR 104.
Nevertheless,
GC> > GC> I just tried it now, with this diff vs. HEAD (which uses 'git diff
-U0'
GC> > GC> for extreme terseness):
GC> > GC>
GC> > GC> diff --git a/stream_cast_test.cpp b/stream_cast_test.cpp
GC> > GC> index d391ed6f..f7d471cd 100644
GC> > GC> --- a/stream_cast_test.cpp
GC> > GC> +++ b/stream_cast_test.cpp
GC> > GC> @@ -71 +71 @@ To cast_2(From from, To = To())
GC> > GC> -std::stringstream& imbued()
GC> > GC> +std::stringstream imbued()
GC> > GC> @@ -75 +75 @@ std::stringstream& imbued()
GC> > GC> - return interpreter;
GC> > GC> + return std::move(interpreter);
GC> > GC> @@ -83 +83 @@ To cast_3(From from, To = To())
GC> > GC> - std::stringstream& interpreter {imbued()};
GC> > GC> + std::stringstream&& interpreter {imbued()};
GC> [...]
GC> > I'd actually write this without "&&" in the last 2 chunks, i.e. I'd just
GC> > use an object:
GC> >
GC> > std::stringstream interpreter {imbued};
GC>
GC> Please help me understand what difference this makes.
Your version creates a temporary object, which is the result returned by
the function imbued() and binds a reference to it. My version creates a new
local object using move ctor from this temporary object, i.e. it requires
an extra step logically, but it's expected that it will be optimized to
the same code and the version without "&&" is simpler.
GC> But if I omit '&&' in the last two chunks and repeat the measurement,
GC> the timing is the same, so is the code with '&&' omitted actually
GC> identical?
Due to NRVO it actually should be. In fact, I'd expect any optimizing
compiler to inline the whole imbued() into the caller anyhow.
GC> With the omission, as you suggest:
GC> std::stringstream interpreter {imbued()};
GC> clearly we're constructing a new object. I was hoping that adding '&&'
GC> thus:
GC> std::stringstream&& interpreter {imbued()};
GC> would avoid construction overhead
But it still has to construct the object inside imbued(). Because of NRVO
the compiler can actually just reuse this object in the caller (the class
still has to be movable for this to work, however, if stringstream were not
movable, your version would be the only way to make it work -- but it's
pretty strange to have non-movable objects).
GC> But removing '&&' produced no timing difference, so clearly my hopes are
GC> not being realized. Why not? Is a new object actually being constructed
GC> even with '&&'? If so, why doesn't writing '&&' prevent that?
No, a new object is constructed in both cases, but only once, due to an
optimization explicitly mandated by the Standard precisely in order to make
simple code like my version above work optimally.
GC> And, BTW, if my hopes were realized, then wouldn't the object that's
GC> supposedly being moved attain a "valid but unspecified" state, such
GC> that moving from it repeatedly in a timing loop would be unlikely to
GC> do the right thing after the first iteration?
Well, no, this object is temporary anyhow, so we don't reuse it. Or maybe
I'm misunderstanding which version are we speaking about here?
GC> Furthermore, now I come across this article:
GC>
https://stackoverflow.com/questions/18766324/is-it-useless-to-declare-a-local-variable-as-rvalue-reference-e-g-t-r-move
GC> |
GC> | AnyTypeMovable v;
GC> | AnyTypeMovable&& r = move(v);
GC> |
GC> | I'd say it's rather useless since r is now an lvalue (it has a name!)
GC> | ...
GC> | a named rvalue-reference is an lvalue
GC>
GC> Is that last statement true?
Yes, I think so.
GC> If so, isn't it an antinomy?
But what else can it be?
GC> And if it's useless to declare a local variable of rvalue-reference
GC> type, then why does N2027 declare such a variable?
I think it does it mostly as a demonstration of the concept of rvalue
references. At least, I struggle to think of any situation in which it
would be useful to do this outside of template code (except for the already
mentioned rare case of non-movable types).
Regards,
VZ
Re: [lmi] Micro-optimization in ledger_format, Greg Chicares, 2019/01/18