• How to transfer an allocated object into a function closure

    From Marcel Mueller@news.5.maazl@spamgourmet.org to comp.lang.c++ on Fri Mar 14 20:36:07 2025
    From Newsgroup: comp.lang.c++

    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
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Paavo Helde@eesnimi@osa.pri.ee to comp.lang.c++ on Fri Mar 14 22:40:40 2025
    From Newsgroup: comp.lang.c++

    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




    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Marcel Mueller@news.5.maazl@spamgourmet.org to comp.lang.c++ on Sat Mar 15 10:07:03 2025
    From Newsgroup: comp.lang.c++

    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
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Bonita Montero@Bonita.Montero@gmail.com to comp.lang.c++ on Sat Mar 15 10:34:41 2025
    From Newsgroup: comp.lang.c++

    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.

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Marcel Mueller@news.5.maazl@spamgourmet.org to comp.lang.c++ on Sun Mar 16 10:02:50 2025
    From Newsgroup: comp.lang.c++

    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

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Bonita Montero@Bonita.Montero@gmail.com to comp.lang.c++ on Sun Mar 16 14:07:00 2025
    From Newsgroup: comp.lang.c++

    Am 16.03.2025 um 10:02 schrieb Marcel Mueller:

    How can I move a lambda into a std::function?

    If you pass a temporary to the function<> constructor it's automatically
    moved. If you like to pass a object not declared inside the function's constructor-parameters you've to move() it. If you like not to have
    external allocation you could pass it with a reference_wrapper, but
    then you've to take care that the actual generic function object
    outlives the function-object.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From usenet@usenet@stegropa.de (Stefan =?utf-8?Q?Gro=C3=9Fe?= Pawig) to comp.lang.c++ on Sun Mar 16 18:43:12 2025
    From Newsgroup: comp.lang.c++

    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
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Bonita Montero@Bonita.Montero@gmail.com to comp.lang.c++ on Tue Mar 18 13:18:50 2025
    From Newsgroup: comp.lang.c++

    Am 16.03.2025 um 18:43 schrieb Stefan Große Pawig:

    The functor that is passed to std::function has to be copy-constructible (20.8.11.2.1/7 in C++11).

    I asked myself why a function<>-object needs a copyable target when
    the function<>-object isn't constructed with copying but with moving.
    Then I had the idea that deleting, copying and moving the target
    inside the function<>-object must be virtual, i.e. when the function<>
    object is initialized these three operations have to be initialized as function-pointers. This requires copyability of the target at creation
    time even if the target is moved inside the function<>-object.

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From usenet@usenet@stegropa.de (Stefan =?utf-8?Q?Gro=C3=9Fe?= Pawig) to comp.lang.c++ on Sat Mar 22 22:44:33 2025
    From Newsgroup: comp.lang.c++

    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
    --- Synchronet 3.20c-Linux NewsLink 1.2