The reason for me to ask this is I need to store std::function in a vector, and the in-house vector we have in company basically is doing realloc if it needs more memory. (Basically just memcpy, no copy/move operator involves)
This means all the element we can put in our container need to be trivially-copyable.
Here is some code to demonstrate the problematic copy I had:
void* func1Buffer = malloc(sizeof(std::function<void(int)>));
std::function<void(int)>* func1p = new (func1Buffer) std::function<void(int)>();
std::function<void(int)>* func2p = nullptr;
*func1p = [](int) {};
char func2Buffer[sizeof(*func1p)];
memcpy(&func2Buffer, func1p, sizeof(*func1p));
func2p = (std::function<void(int)>*)(func2Buffer);
// func2p is still valid here
(*func2p)(10);
free(func1Buffer);
// func2p is now invalid, even without std::function<void(int)> desctructor get triggered
(*func2p)(10);
I understand we should support copy/move of the element in order to store std::function safely.
But I am still very curious about what is the direct cause of invalid std::function copy above.
----------------------------------------------------UpdateLine----------------------------------------------------
Updated the code sample.
I have found the direct reason for this failure, by debugging our in-house vector more.
The trivially copied std::function has some dependency on original object memory, delete the original memory will trash the badly copied std::function even without the destruction of the original object.
Thanks for everyone's answer to this post. It's all valuable input. :)
The problem is how
std::functionhas to be implemented: it has to manage the lifetime of whatever object it's holding onto. So when you write:we must invoke the destructor of
Xwhenfgoes out of scope. Moreover,std::functionwill [potentially] allocate memory to hold thatXso the destructor offmust also [potentially] free that memory.Now consider what happens when we try to do:
At the point we're calling the function "stored" at
buffer, theXobject has already been destroyed and the memory holding it has been [potentially] freed. Regardless of whetherXwereTriviallyCopyable, we don't have anXanymore. We have the artist formerly known as anX.Because it's incumbent upon
std::functionto manage its own objects, it cannot beTriviallyCopyableeven if we added the requirement that all callables it managed wereTriviallyCopyable.To work in your
realloc_vector, you need either need something likefunction_ref(orstd::function<>*) (that is, a type that simply doesn't own any resources), or you need to implement your own version offunctionthat (a) keeps its own storage as a member to avoid allocating memory and (b) is only constructible withTriviallyCopyablecallables so that it itself becomes trivially copyable. Whichever solution is better depends on the what your program is actually doing.