Boost logo

Boost Users :

Subject: [Boost-users] Aliased parameters in boost::bind
From: Evgeny Fraimovitch (evgeny_at_[hidden])
Date: 2017-03-29 17:46:35


Hello,

The tutorial for Boost.Bind library contains the following sample code:
        bind can handle functions with more than two arguments, and its
argument substitution mechanism is more general:
        bind(f, _2, _1)(x, y); // f(y, x)
        bind(g, _1, 9, _1)(x); // g(x, 9, x)
        bind(g, _3, _3, _3)(x, y, z); // g(z, z, z)
        bind(g, _1, _1, _1)(x, y, z); // g(x, x, x)

As can be seen, all but the first of those samples alias the placeholder
parameters, substituting a single passed argument several times.
What is not mentioned in the tutorial
(http://www.boost.org/doc/libs/1_63_0/libs/bind/doc/html/bind.html#bind.purp
ose.using_bind_with_functions_and_fu) is the fact that such aliasing for any
parameter with nontrivial move behavior is unexpected and possibly
dangerous.

For instance, given the function:
void f(std::string x, std::string y, std::string z) {
        std::cout << x << y << z;
}
One could following the tutorial naively write:
auto triple = boost::bind(f, _1, _1, _1);

and this would even work for:
std::string x = "a pretty long string";
triple(x);
printing the string thrice, as expected.
However the result of triple(std::string("a pretty long string")) would be
the string only printed once, which is hardly what the user would expect.
In fact, any bind expression produced with aliasing would be sensitive to
the type of the reference passed, violating the functor abstraction badly.

So, the question is:
1. This behavior seems to match the std::bind behavior documented in the
standard. However, would it not be wise to warn against parameter aliasing
in the tutorial then? (instead of demonstrating it as one of the first
samples)
2. Maybe we can actually check if a parameter is aliased in boost::bind and
copy it if it is - I have not tried it, but I think it can be done. Would it
be a more sensible thing to do?

The sample above might seem contrived, but I've actually encountered this
bug in production code when porting it to boost 1.63 (the boost.signals code
implicitly does boost::forward, so it was not outwardly apparent what was
happening)

Sincerely yours,
     Evgeny


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net