I have allocated objects like GFile* or whatever that are not copyable,
at least not cheap.
This objects should be passed to a std::function object that takes the ownership.
Normally I would use unique_ptr with move semantics. But for some reason
the function objects wants to create a copy of the unique_ptr.
In fact I allocate the function object on the heap and pass it to
another thread that takes the ownership.
It is a GTK application with C++14.
guint gIdleAdd(std::function<void()>* func, gint priority)
{ return g_idle_add_full(
G_PRIORITY_DEFAULT_IDLE,
[](void* user_data)
{ (*static_cast<std::function<void()>*>(user_data))();
return G_SOURCE_REMOVE;
},
func,
[](void* user_data)
{ delete static_cast<std::function<void()>*>(user_data);
});
}
This works fine:
(xPtr is a intrusive reference counted smart pointer.)
gIdleAdd(new function<void()>([that = xPtr<ReplayGainWorker>(this),
error]()
{ that->OnFinished(error); }));
But this does not work:
template <typename T, typename D>
std::unique_ptr<T, D> make_unique(T* ptr, D deleter)
{ return std::unique_ptr<T, D>(ptr, deleter);
}
GError* error;
...
gIdleAdd(new std::function<void()>([error = make_unique(error, g_error_free)]()
{ OnDirFailed(nullptr, error.get()); }));
g_error_free needs to be invoked exactly once after the function has
been called or the event is cancelled, i.e. when the function object is deleted.
In general, passing non-copyable objects to a lambda should be done via std::move() (requires C++14):
auto u = std::make_unique<FOO>();
bar( [ u = std::move(u) ]() { /*...*/ } );
/usr/include/c++/9/bits/std_function.h:176:6: error: use of deleted
function ‘ReadDirectoryWorker::DirScan(gObject<_GFileEnumerator>)::<lambda()>::<lambda>(const ReadDirectoryWorker::DirScan(gObject<_GFileEnumerator>)::<lambda()>&)’
Am 15.03.2025 um 10:07 schrieb Marcel Mueller:
/usr/include/c++/9/bits/std_function.h:176:6: error: use of deleted
function
‘ReadDirectoryWorker::DirScan(gObject<_GFileEnumerator>)::<lambda()>::<lambda>(const ReadDirectoryWorker::DirScan(gObject<_GFileEnumerator>)::<lambda()>&)’
You're trying to copy the lambda but you have to move it.
How can I move a lambda into a std::function?
Am 14.03.25 um 21:40 schrieb Paavo Helde:
In general, passing non-copyable objects to a lambda should be done via
std::move() (requires C++14):
auto u = std::make_unique<FOO>();
bar( [ u = std::move(u) ]() { /*...*/ } );
I know. I tried this first, but I still get the same error:
auto u(make_unique(child_error, g_error_free));
gIdleAdd(new function<void()>([child_dir = move(child_dir), child_error = move(u)]()
{ OnDirFailed(child_dir.get(), child_error.get()); }));
/usr/include/c++/9/bits/std_function.h:176:6: error: use of deleted function ‘ReadDirectoryWorker::DirScan(gObject<_GFileEnumerator>)::<lambda()>::<lambda>(const
ReadDirectoryWorker::DirScan(gObject<_GFileEnumerator>)::<lambda()>&)’
...
src/easytag.cc:1144:87: error: use of deleted function ‘std::unique_ptr<_Tp,
::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = _GError; _Dp = void (*)(_GError*)]’
Not the lambda but std::function is the problem.
The functor that is passed to std::function has to be copy-constructible (20.8.11.2.1/7 in C++11).
Hi Marcel!
Marcel Mueller <news.5.maazl@spamgourmet.org> writes:
Am 14.03.25 um 21:40 schrieb Paavo Helde:
In general, passing non-copyable objects to a lambda should be done via
std::move() (requires C++14):
auto u = std::make_unique<FOO>();
bar( [ u = std::move(u) ]() { /*...*/ } );
I know. I tried this first, but I still get the same error:
auto u(make_unique(child_error, g_error_free));
gIdleAdd(new function<void()>([child_dir = move(child_dir), child_error =
move(u)]()
{ OnDirFailed(child_dir.get(), child_error.get()); }));
/usr/include/c++/9/bits/std_function.h:176:6: error: use of deleted function
‘ReadDirectoryWorker::DirScan(gObject<_GFileEnumerator>)::<lambda()>::<lambda>(const
ReadDirectoryWorker::DirScan(gObject<_GFileEnumerator>)::<lambda()>&)’
...
src/easytag.cc:1144:87: error: use of deleted function ‘std::unique_ptr<_Tp,
::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = _GError; _Dp =void (*)(_GError*)]’
Not the lambda but std::function is the problem.
The functor that is passed to std::function has to be copy-constructible (20.8.11.2.1/7 in C++11).
If you can use C++23, there is std::move_only_function. <https://en.cppreference.com/w/cpp/utility/functional/move_only_function>
Regards,
Stefan
Sysop: | DaiTengu |
---|---|
Location: | Appleton, WI |
Users: | 1,029 |
Nodes: | 10 (1 / 9) |
Uptime: | 182:15:16 |
Calls: | 13,337 |
Calls today: | 4 |
Files: | 186,574 |
D/L today: |
5,448 files (1,505M bytes) |
Messages: | 3,356,610 |