• How to transfer an allocated object into a function closure

    From Marcel Mueller@21:1/5 to All on Fri Mar 14 20:36:07 2025
    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.


    Any ideas?


    Marcel

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to Marcel Mueller on Fri Mar 14 22:40:40 2025
    On 14.03.2025 21:36, Marcel Mueller wrote:
    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) ]() { /*...*/ } );

    HTH
    Paavo

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Marcel Mueller@21:1/5 to All on Sat Mar 15 10:07:03 2025
    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, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = _GError; _Dp = void (*)(_GError*)]’


    Not the lambda but std::function is the problem.


    Marcel

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Marcel Mueller@21:1/5 to All on Sun Mar 16 10:02:50 2025
    Am 15.03.25 um 10:34 schrieb Bonita Montero:
    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?


    Marcel

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan =?utf-8?Q?Gro=C3=9Fe?= Pawig@21:1/5 to Marcel Mueller on Sun Mar 16 18:43:12 2025
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan =?utf-8?Q?Gro=C3=9Fe?= Pawig@21:1/5 to usenet@stegropa.de on Sat Mar 22 22:44:33 2025
    usenet@stegropa.de (Stefan Große Pawig) writes:
    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

    BTW, now that https://www.youtube.com/watch?v=clpQVn_LAiM is out: maybe
    the MoveWrapper introduced around 30:30 helps in your case, too.

    Regards,
    Stefan

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)