-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Add a life support system for type_caster temporaries (+ binary size reduction) #924
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This generally looks great. However, one issue that should be considered here is that local static variables like |
I was thinking of something like this; 👍 for implementing it. Also good for catching the using namespace Eigen;
void some_func(Ref<MatrixXd> x) { /* do something with x */ }
some_func(py::cast<Ref<MatrixXd>>(myarray)); With this PR that now raises an exception, which is good (it would be nicer still to make that work, but that doesn't really seem feasible). The one issue I see is that with the life support instance being outside the As for lifetime, I'm a bit concerned that this approach has the potential to vastly extend the lifetime of temporaries: it seems as though no pybind11 function call is ever going to result in freeing the temporaries when there is some pybind11 function call somewhere up the stack. If all my pybind11 functions are short, that's not an issue, but if a pybind function call sits high up the stack (e.g. perhaps it calls a python function that does significant work) this is going to build up temporaries without freeing them for potentially a very long time. An alternative approach would be to get rid of the nesting and counter, and have |
1a3bceb
to
87c1fa1
Compare
Very good points. I've made the appropriate changes. The patients are now stashed in I've now added tests for py::class_<A>(m, "A");
py::class_<B>(m, "B").def(py::init<A>());
py::implicitly_convertible<A, B>();
// when inside a bound function...
m.def("foo", []() {
auto obj = py::cast(A{});
const auto &b = obj.cast<const B&>(); // reference to temporary
// ... use b -- previously dangling reference, now works
auto str_obj = ...; // some string which requires an encoding change
auto s = str_obj.cast<std::string_view>();
// ... use s -- also works now
}); Is there any reason to not allow this? I suppose there could be a danger of creating too many temp objects (which are only destroyed on |
87c1fa1
to
88f5f29
Compare
include/pybind11/cast.h
Outdated
if (level() == 0) | ||
patients() = PyList_New(0); | ||
++level(); | ||
get_internals().loader_patient_stack.push_back(PyList_New(0)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like it's going to be creating a lot of lists here, the vast majority of which are never used (i.e. life support is the exception rather than the rule). Is there a reason to prefer always allocating here to allocating the list on demand when the first add_patient
is called?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, there's no need to allocate the list in the majority of cases. Fixed.
Ah, I hadn't thought about the life support already being present; that's a nice feature. |
This looks good to me! |
Put the caster's temporary array on life support to ensure correct lifetime when it's being used as a subcaster.
61ff4e2
to
3f92071
Compare
The first commit here changes the handling of temporary objects created by
type_caster::load()
. It uses an RAIIloader_life_support
class, placed indispatcher
, which holds a list of patients only for the lifetime of the function call. This has two nice advantages:type_caster_generic
to this system reduced the binary size of the test module by 3-4% (!), depending on the compiler. The main reason seems to be the removal ofobject temp
fromtype_caster_generic
, which makes the struct trivially copyable.The second commit fixes #916 (alternative to #917) by using the new system in the
Eigen::Ref
caster.