4 ms·
Why not just pass around an std::pair<void(*)(FuncData*), std;:unique_ptr<FuncData>> at this stage? This implementation has a bunch of performance and erg
by cherryteastain 1y ago
Why not just pass around an
std::pair<void(*)(FuncData*), std;:unique_ptr<FuncData>>
at this stage? This implementation has a bunch of performance and ergonomics issues due to things like not using perfect forwarding for the Func1::Call(T) method, so for anything requiring copying or allocating it'll be a decent bit slower and you'll also be unable to pass anything that's noncopyable like an std::unique_ptr.
- kjksf 1y agoI don't know fancy C++ so I don't understand your point about perfect forwarding. But I do know the code I write and you're wrong about performance of Func0 and Func1. Those are 2 machine words and all it takes to construct them or copy them is to set those 2 fields. There's just no way to make it faster than that, both at runtime or at compile time. The whole point of this implementation was giving up fancy features of std::function in exchange for code that is small, fast (both runtime and at compilation time) and one that I 100% understand in a way I'll never understand std::function.
- cherryteastain 1y agoIn this function void Call(T arg) const { if (fn) { fn(userData, arg); } } Say you pass something like an std::vector<double> of size 1 million into Call. It'll first copy the std::vector<double> at the point you invoke Call, even if you never call fn. Then, if fn is not nullptr, you'll then copy the same vector once more to invoke fn. If you change Call instead to void Call(T&& arg) const { if (fn) { fn(userData, std::forward<T>(arg)); } } the copy will not happen at the point Call is invoked. Additionally, if arg is an rvalue, fn will be called by moving instead of copying. Makes a big difference for something like std::vector<double> foo(); void bar(Func1<std::vector<double>> f) { auto v = foo(); f(std::move(v)); }
- OskarS 1y ago> But I do know the code I write and you're wrong about performance of Func0 and Func1. Those are 2 machine words and all it takes to construct them or copy them is to set those 2 fields. You also have to heap allocate your userData, which is something std::function<> avoids (in all standard implementations) if it’s small enough (this is why the sizeof() of std::function is larger than 16 bytes, so that it can optionally store the data inline, similar to the small string optimization). The cost of that heap allocation is not insignificant. If I were doing this, I might just go the full C route and just use function pointers and an extra ”userData” argument. This seems like an awkward ”middle ground” between C and C++.
- badmintonbaseba 1y agoJust use std::function, you don't have to pass a lambda. Any callable is fine.