Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Undefined results with std::bind and duplicate placeholders

Tags:

c++

c++11

I'm having some trouble understanding something from the notes section for std::bind on the cppreference page: it says that when duplicate placeholders appear in the same bind expression-such as multiple _1's-the results are only well-defined only if u1 is an lvalue or non-movable rvalue. Can someone give an example where it would not be well-defined?

like image 507
Dongie Agnir Avatar asked Aug 25 '14 02:08

Dongie Agnir


1 Answers

The following is probably the simplest example I can think of (and considering my familiarity with rvalues, this is pushing my limits).

First the code (probably too simple, but I think it is correct for demonstration):

#include <iostream>
#include <utility>
#include <functional>

struct Obj
{
    Obj()
    {
        std::cout << __PRETTY_FUNCTION__ << '\n';
    }

    Obj(Obj const&)
    {
        std::cout << __PRETTY_FUNCTION__ << '\n';
    }

    Obj(Obj&&)
    {
        std::cout << __PRETTY_FUNCTION__ << '\n';
    }
};

void foo(Obj, Obj)
{
    std::cout << __PRETTY_FUNCTION__ << '\n';
}

int main()
{
    using namespace std::placeholders;
    auto fn = std::bind(foo, _1, _1);
    fn(Obj());
}

Output

Obj::Obj()
Obj::Obj(Obj &&)
Obj::Obj(Obj &&)
void foo(Obj, Obj)

What is important is the clear evidence only one Obj was initially constructed, but was subsequently "moved" twice, which is a no-no for move-semantics. Once the first move is complete, the object is in purgatory. The second move is not well-defined, since the source object is no longer well-defined. The repetitive placeholder cannot be a movable rvalue or what you see here can happen.

like image 163
WhozCraig Avatar answered Nov 11 '22 03:11

WhozCraig