+3

Copying a std::function object to another std::function

I have the following declaration of a binary search tree: template<class Type, class Predicate = std::less<Type>> binary_search_tree; In this class, along with a root node, I store a std::function object to be used as the comparison predicate during insert operations. I now had to make a function to generate the mirror image of a binary_search_tree object. In the function implemented for the same, after performing the required operations, I assign a new comparison predicate to the mirrored object: mirror_bst.compare = [this](value_type v1, value_type v2)->bool{ return !this->compare(v1,v2); }; Now, when I try to copy the returned object to a newly created object, the program crashes. Backtracing in GDB shows a SIGSEGV raised in the following call: 0x0000000000404ba0 in std::function<bool (int, int)>::operator()(int, int) const ( __args#1=<optimized out>, __args#0=<optimized out>, this=<optimized out>) The copy constructor is defined in the following way: binary_search_tree(const binary_search_tree& bst) : binary_search_tree() { compare = bst.compare; bst.traverse_preorder([this](const vertex& node){ this->insert(*node); }); } A move constructor is also defined in the class: binary_search_tree(binary_search_tree&& bst) : binary_search_tree() { compare=std::move(bst.compare); root=bst.root; csize=bst.csize; bst.csize=0; bst.root=bst.end_iter; } When the returned object is moved instead of copied, the program works as expected. Why? Also, if the following line: compare = bst.compare; is commented, the program executes successfully but displays incorrect results due to an incorrect predicate. Why does the program not crash in this case? Link to the complete code: https://code.sololearn.com/cDe9SPnEH3T1/#cpp

10/9/2019 3:37:42 PM

Kinshuk Vasisht

6 Answers

New Answer

+1

It seems to be working - the copying that is. But there appears to be an infinite recurrance into the lambda in line 257 causing a stack overflow. Add a print out in that lambda and you'll see. I hope that helps ...

+2

*** Thank you very much for your help. I did not look at the complete backtrace and so did not notice the recurrence. However, I am still not able to figure out why the recurrence exists as such, and why it is not observed when I move the returned object into another object (auto bst2 = std::move(bst.mirror)) or comment the line: compare = bst.compare in the copy constructor. Can it be that capturing this has something to do with it?

+2

Deep copy vs Shallow copy issue? Recently studied , have not tried yet. https://owlcation.com/stem/Copy-Constructor-shallow-copy-vs-deep-copy

+1

I think what you have created through the assignment bst = bst2 is a complicated form of bool compare(int n, int m) { return !compare(n,m); } The this pointer might well play a role. What might work is to use enable_shared_from_this and rewrite using shared pointers. But I am just guessing myself at this point.

+1

*** Thank you for the suggestions. I'll try using shared pointers for a solution. For the time being, I'll just try to avoid copying objects and move them instead whenever possible, which is at times a good thing, I suppose.

+1

Manual Thank you for the link. However, as identified by ***, the problem was not with the copying in general, but instead the lambda being called inside the copy assignment operator or the copy constructor. In my copying functions, I reiterate over all the nodes of the tree passed as argument and add new copies of each node to the tree being constructed or assigned. But yes, it might be that the lambda itself is not copied properly, and as a result there is a dangling reference, which might be leading to the infinite recurrence. I am not sure, however.