Reputation: 17241
The following example is a simplified version found in production code
#include <string>
#include <functional>
#include <iostream>
#include <vector>
struct A
{
std::string myString = "World";
};
struct B
{
void operator()()
{
std::cout << a.myString;
}
const A& a;
};
std::vector<std::function<void()>> v;
void Store(std::function<void()> myFunc)
{
v.emplace_back(myFunc);
}
void Print()
{
v[0]();
}
int main()
{
A a; a.myString = "Hello";
Store(B{a}); // temporary passed with a const-ref of on-the-stack `A`
Print();
}
In production code, accessing the string A
(i.e. invoking the function through the vector
which in turn accesses myString
in A
) results in a crash. Compiler Explorer seems to be okay with it, however if this behaviour is undefined, the output probably cannot be trusted: https://godbolt.org/z/cPPKeK9zd
Assuming this is undefined behaviour and I can only store a const &
to A
, what can I do in the Store(...)
function to issue a compiler error and try to catch the undefined behaviour at compile time.
Upvotes: 0
Views: 76
Reputation: 7428
This example has no undefined behavior.
Calling Store
copy-initializes the argument of type std::function<void()>
from the temporary object of type B
. In doing so, std::function
uses perfect forwarding to initialize its own internal object of type B
, which is therefore move-constructed from the original temporary.
The call to emplace_back
copy-constructs the function which therefore copy-constructs the internal object of type B
.
That the initial B
object is a temporary is irrelevant, as the copy inside the function inside the vector is not. The reference to A
inside this B
copy still points to the same A
object, which is still within its lifetime.
Upvotes: 2