-----Original Message----- From: Boost-users [mailto:boost-users-bounces@lists.boost.org] On Behalf Of Gavin Lambert via Boost-users Sent: Thursday, March 30, 2017 6:09 AM To: boost-users@lists.boost.org Cc: Gavin Lambert
Subject: Re: [Boost-users] Aliased parameters in boost::bind On 30/03/2017 11:59, Evgeny Fraimovitch wrote:
Although the code is suboptimal, I do not agree it is bad. This lack of pass by reference in this case should not be affecting correctness, since we are not going to modify the object. Also, it might not be std::string. Shared points are often passed by value and they exhibit the same issue. They can be passed as const reference too, as an optimization, however whether this justifies additional clutter in the parameter list is a matter of personal taste.
Perhaps this is a domain-specific concern, but where I work you get severely beaten* if you pass strings *or* shared_ptrs by value. (Or in general anything with non-trivial copy semantics.)
(* or at least mocked at the water cooler and code reviews) I agree it is very important for performance critical code, much less so for utility code which won't be invoked in tight loops. Anyway, I consider being mocked at water cooler being better than the compiler silently corrupting
the code on boost version transition.
Neither memory allocations nor atomic refcount adjustments are free, and the function call boundary is rarely the correct place for them to occur.
But yes, ideally this would produce correct output despite being suboptimal. It's one of the unfortunate side effects of perfect forwarding.
Having said that, with the existence of perfect forwarding it means you're using C++11, which means you could use lambdas instead of using bind. They don't suffer the same issue because they don't use perfect forwarding:
auto triple = [](std::string x) { f(x, x, x); }; auto triple = [](std::string const& x) { f(x, x, x); }; auto triple = [](std::string && x) { f(x, x, x); };
Substituting any of these produces correct output; you would only provoke the incorrect output if you explicitly std::move(x) in the last version, which is an obvious programmer error.
Using lambdas is exactly how I worked around for it in the place that originally aliased parameters. What I am saying is, though, the Boost.Bind tutorial should not promote parameter aliasing, since it obviously produces extremely fragile code. I believe forwarding twice anything is a *mistake*, it's just a harmless one, when the type has trivial move semantics.
It can be most problematic for large codebases with existing pre-C++11
bind
code, of course, that is later updated to C++11. Hopefully you have unit tests to catch these sorts of things. :)
Well, this instance got caught by a unit test. However, when something as fundamental as parameter passing is concerned you start wondering how well you cover that.
There's some other corner cases with bind that are a bit weird, for
given:
void g(std::string&& x) { std::string y(std::move(x)); std::cout << y << std::endl; }
(which is even worse than pass-by-value in this case, of course.) This compiles and works as expected:
auto fn = boost::bind(g, _1); fn(std::string("some string"));
As does this:
std::string x("some string"); auto fn = boost::bind(g, _1); fn(std::move(x));
But this fails to compile:
std::string x("some string"); auto fn = boost::bind(g, std::move(x)); fn();
Even though logically they ought to be the same. (The reason this happens AFAIK is because fn could be called more than once, but wouldn't be in a valid state after the first time; I think someone decided this should be a compile error rather than throwing an exception if you do happen to call it twice. It does compile if g doesn't have an rvalue-reference parameter.)
Ironically this is actually one of the scenarios where bind was still superior to lambdas in C++11. Given void g(std::string const& x), you can compile
example, that
same last block of code just fine (even with the move), but you couldn't write an equivalent lambda (without contortions) since they lacked move- capturing. This has been fixed in C++14 though, albeit a bit wordy.
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users