Boost logo

Boost :

Subject: Re: [boost] [move] BOOST_RV_REF(TypeWithoutMoveEmulation) parameters
From: danny kabrane (dkabrane_at_[hidden])
Date: 2017-05-23 05:41:26


> As an example, given this C++11 code:
>
> void Foo::StringSink(std::string&& s) { ... }
> ...
> void Bar::SomeEventHandler() {
> this->foo->StringSink(std::move(this->stringMember)); // stringMember
is never used after this point
> }
>
> I'd like to be able to emulate that in C++98 ala
>
> void Foo::StringSink(BOOST_RV_REF(std::string) s) { ... }
> ...
> void Bar::SomeEventHandler () {
> this->foo->StringSink(boost::move_any(this->stringMember)); //
stringMember is never used after this point
> }
> Boost.Move allows me to do this, but only if the type passed to
boost::move() is itself move enabled. Which IMO is an unnecessary
restriction.

In C++98 you can pass a parameter that is not movable (meaning, implements
internal boost::rv facility) to boost::move it will just send a reference
to it.
If the type doesn't implements boost::rv, I think you're stuck with copies
and such, so it's not an unnecessary restriction.

As for stl containers such as std::string or std::vector, you could use
boost::container::string (vector, etc.), they emulate move semantics for
C++98 compilers, and as far as I used them in my applications, in most
cases they outperform stl containers.

But the main drawback that comes with this workaround is the
interoperability with other APIs that use std::string (or other) because
they don't know boost::container, so you have to write more code that
handle this use case.

Regards
Danny

2017-05-22 10:44 GMT+02:00 Groke, Paul via Boost <boost_at_[hidden]>:

> On Monday, 22. Mai 2017 03:21, Gavin Lambert wrote:
> > > I just assumed that this was possible by simply passing the argument
> > > with boost::move(arg). Apparently it's not though, because boost::move
> > > will return a plain T& for types without move emulation.
> > > For the time being I have defined my own helper function template
> > > "move_any" that will always return a rv<T>&.
> > >
> > > Is there such a function that I missed? And if not, would you think
> > > it'd make sense to provide one (I certainly think it would)?
> >
> > Apologies for the prior blank reply; accidentally fat-fingered the Send
> button.
> >
> > I don't think this makes sense. The Boost.Move emulation library is
> exactly
> > that -- an as-close-to-possible *emulation* of rvalue-reference-based
> C++11
> > move for pre-C++11 compilers. As such it is naturally designed for
> > modification of the type-to-be-moved (it requires adding move
> constructors
> > etc as applicable).
> >
> > Additionally, when actually compiled in C++11 it gracefully upgrades to
> actual
> > rvalue references -- as such the rv<T> class disappears entirely; this
> is an
> > implementation detail and you're not supposed to use it outside of the
> > macros in the documented interface of Boost.Move. (Also, I have grave
> > doubts that returning one by reference could be correct code, as they're
> > typically locally constructed IIRC.)
>
> I'm sorry, I guess that was confusing. My "move_any" function does of
> course return an rvalue reference in >= C++11 mode. It just doesn't behave
> differently for types that are not move-enabled in C++98 mode. Regarding
> returning boost::rv by reference - I didn't invent that, that's exactly
> what Boost.Move does. It's a necessary hack to allow Boost.Move to work
> more or less transparently. I simply copied the definition of boost::move
> sans the "should I return boost::rv<T>& for this type" checks in C++98 mode.
>
> > If you want to write some generic code around swap(), then do that; this
> > exists for both C++11 and prior.
>
> I want to write sink functions that can "consume" a value. They're not
> member functions of the class they're consuming. In C++11 I would use
> rvalue references for this. In C++98 I don't know any elegant way of
> expressing this. Of course I could write the function to take a normal
> lvalue reference, but that's not visible at the call site. If I use
> BOOST_RV_REF instead, then it becomes visible at the call site because the
> caller explicitly has to write "move", which IMO is a great improvement. Of
> course I could use my own helper type for this. But since everything
> (except the "move_any" function) is already there in Boost.Move, and I also
> want to fully move-enable some types in the future using Boost.Move (which
> would require interoperability between my own solution and Boost.Move), I'd
> like to use Boost.Move/BOOST_RV_REF for it.
>
> As an example, given this C++11 code:
>
> void Foo::StringSink(std::string&& s) { ... }
> ...
> void Bar::SomeEventHandler() {
> this->foo->StringSink(std::move(this->stringMember)); // stringMember
> is never used after this point
> }
>
> I'd like to be able to emulate that in C++98 ala
>
> void Foo::StringSink(BOOST_RV_REF(std::string) s) { ... }
> ...
> void Bar::SomeEventHandler () {
> this->foo->StringSink(boost::move_any(this->stringMember)); //
> stringMember is never used after this point
> }
>
> Boost.Move allows me to do this, but only if the type passed to
> boost::move() is itself move enabled. Which IMO is an unnecessary
> restriction.
>
> > Also, be careful with move. It's a shiny new toy so people are excited
> to play
> > with it, but if not used carefully (*especially* with a
> > non-C++11 STL) it can easily lead to incorrect behaviour or degraded
> > performance. Learn both when and when *not* to use it.
>
> I don't want to come across as confrontational, but ... what makes you
> think I don't know when and when not to use it?
> I'm working with more or less performance critical code here. Not so much
> that I can warrant writing code that's very hard to write and very hard to
> understand for the sake of performance. Which is why I don't want to use T&
> for my sink parameters. But it's definitely code where I don't want to copy
> e.g. a std::string if I don't have to copy it. And there are quite a few
> places where I have to "move" strings (or objects containing strings)
> around, where I cannot use C++98 copy elision stuff.
>
> And regarding implementation details: One of the reasons why I would want
> this to be implemented in Boost.Move is that I don't want my code to rely
> on the internals of Boost.Move.
>
> Regards,
> Paul Groke
>
>
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/
> mailman/listinfo.cgi/boost
>


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk