Reimplement py::init<...> to use common factory code

This reimplements the py::init<...> implementations using the various
functions added to support `py::init(...)`, and moves the implementing
structs into `detail/init.h` from `pybind11.h`.  It doesn't simply use a
factory directly, as this is a very common case and implementation
without an extra lambda call is a small but useful optimization.

This, combined with the previous lazy initialization, also avoids
needing placement new for `py::init<...>()` construction: such
construction now occurs via an ordinary `new Type(...)`.

A consequence of this is that it also fixes a potential bug when using
multiple inheritance from Python: it was very easy to write classes
that double-initialize an existing instance which had the potential to
leak for non-pod classes.  With the new implementation, an attempt to
call `__init__` on an already-initialized object is now ignored.  (This
was already done in the previous commit for factory constructors).

This change exposed a few warnings (fixed here) from deleting a pointer
to a base class with virtual functions but without a virtual destructor.
These look like legitimate warnings that we shouldn't suppress; this
adds virtual destructors to the appropriate classes.
This commit is contained in:
Jason Rhinelander
2017-08-17 00:01:42 -04:00
parent 464d98962d
commit c4e180081d
8 changed files with 84 additions and 54 deletions

View File

@@ -274,8 +274,9 @@ TEST_SUBMODULE(factory_constructors, m) {
}
int i;
};
// Workaround for a `py::init<args>` on a class without placement new support
// As of 2.2, `py::init<args>` no longer requires placement new
py::class_<NoPlacementNew>(m, "NoPlacementNew")
.def(py::init<int>())
.def(py::init([]() { return new NoPlacementNew(100); }))
.def_readwrite("i", &NoPlacementNew::i)
;