pybind / pybind/pybind11

function<Type*(void)> will attempt to copy Type on return

Open
#1,041 10 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
18k
Forks
2.3k
Avg merge
5d 17h
Merged PRs (30d)
10

Description

Firstly, thank you for this wonderful library. As I was using it I found some unexpected/undesired behaviour. Wrapped function objects from std::functional will copy the result even when the result is of type pointer.
Here is my sample code to reproduce the issue.

#include <functional>
#include <pybind11/pybind11.h>
#include <pybind11/functional.h>

namespace py = pybind11;

struct Test {
    Test() {};
    Test(const Test &obj) = delete;
    int i;
};
Test* fullFunction()
{
    return new Test();
}
std::function<Test*(void)> func = &fullFunction;

PYBIND11_MODULE(example, m) {
    // optional module docstring
    m.attr("full") = py::cpp_function(func);
    m.attr("func") = func;
    py::class_<Test>(m,"Test")
        .def_readwrite("i",&Test::i);
}
import example
example.full()
example.func()

example.func() will result in an error: return_value_policy = copy, but the object is non-copyable!

It's my understanding that both full & func should return a Test* and that the underlying Test will not be copied however when the pybind11/functional wrapper handles it, it will attempt to copy Test*. I believe this occurs because a function object is an object and not a pointer which causes copy to be the default behaviour that is detected. Sorry if I have misunderstood anything.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in pybind11/functional.h and reproduce the behavior with the C++ and Python examples in the issue, comparing py::cpp_function(func) with the directly exposed function object. Trace how the wrapper selects the return policy for a Test* result; done means example.func() returns the pointer without attempting to copy the non-copyable Test.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, python
Domain
backend-api-design
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.