std::function and std::bind problem.

Hi guys,

I'm experiencing a problem with a bounded function.

In short, I have a CheckState(int) std::function object, to which one of several different functions can be bound. At this point, I'm only using one test function.

The function object and the bound function are members of the same class.
1
2
function<bool(int)> CheckState;
bool CheckState_simple(int v) { return v < memberVar; }


It is bound during the creation of the object.
CheckState = bind(CheckState_simple, this, _1);

I know that the object exists; I can see it is built correctly and works perfectly until it is inside the bound function. Suddenly, it's a corrupt object (looks uninitialized).

If I call the function manually it works fine.
1
2
//	bool check = CheckState(value);  // Enters corrupt object.
	bool check = CheckState_simple(value);  // Works fine.  


I'm using std::bind in several places; this is the only one that seems to be giving problems.

I'm at a loss here. Anyone know what could be happening?
Are you sure you are not copying the owner of memberVar?
Last edited on
I don't think I am.

There is a vector of the owner class. I construct them like this:
1
2
3
4
vector<owner> list_of_owners;
for (ID = 0; ID < owner_count; ++ID) {
    list_of_owners.emplace_back(basic_parameters);
}


The constructor simply initializes the member vars (including one reference) and binds the functions based on input parameters. I tried performing the binds afterwards manually (in case emplace_back has side effects I'm not aware of) to be sure they are being done with the correct object, but there was no change.

I'm not sure that is sufficient to check for copying, but I'm pretty confident there is nothing that can copy or move the object once its emplaced.

Okay, that previous line of thought made it obvious. Both vector::emplace_back and vector::push_back invalidate pointers of the objects already contained.

Ultimately just placing the Bind calls in a second loop, after all objects were constructed, was the obvious solution.

Thanks for the help, Peter87!

[edit]
To clarify, I said before "only this one seems to have problems", but that was because my breakpoints didn't catch the problem. The last object emplaced did have correct pointers (not invalidated due to following emplaces) and passed the checks just fine, and their behavior was much harder to spot when not looking directly at them.

So. Emplace/push_back invalidates pointers, including bound functions.
Last edited on
Gaminic wrote:
Ultimately just placing the Bind calls in a second loop, after all objects were constructed, was the obvious solution.

An alternative solution is to reserve enough space for all elements, before the loop starts, so that the calls to emplace_back don't cause the vector to reallocate.

 
list_of_owners.reserve(owner_count);
Last edited on
Or use a std::deque which won't require any special treatment to work correctly.
Thanks for the tips, guys. std::deque is impractical because of the way I use the data.

I wasn't sure reserve would 100% guarantee no reallocation, but thanks for the suggestion.
This would be more robust:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <functional>
#include <string>
#include <vector>

struct A
{
    A() = default ;
    ~A() noexcept = default ;
    A( std::string str ) noexcept : mem_var( std::move(str) ) {} 
    A( const A& that ) : mem_var(that.mem_var) {} // do not copy initialise check_state
    A( A&& that ) noexcept : mem_var( std::move(that.mem_var) ) {} // do not copy initialise check_state
    A& operator= ( A that ) noexcept { mem_var = std::move(that.mem_var) ; return *this ; } // do not copy assign to check_state

    void call_it( const std::string& str = "test" ) const { check_state(str) ; }

    private:
        std::string mem_var = "default" ;
        const std::function< bool( const std::string& ) > check_state = std::bind( &A::check_it, this, std::placeholders::_1 ) ;
        bool check_it( const std::string& str ) const
        {
            std::cout << "check it - this == " << this
                      << "  mem_var == " << mem_var << " @" << std::addressof(mem_var) << '\n' ;
            return str.size() < mem_var.size() ;
        }
};

int main()
{
    std::vector<A> seq { {"one"}, {"two"}, {"three"} } ; 
    for( const A& a : seq ) a.call_it() ;

    std::cout << "relocate objects\n" ;
    seq.reserve(1000000) ;
    for( const A& a : seq ) a.call_it() ;
}

http://coliru.stacked-crooked.com/a/5385d3928f9e9d01
Topic archived. No new replies allowed.