Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
gaoqiong
pybind11
Commits
7939f4b3
Commit
7939f4b3
authored
Sep 04, 2017
by
Dean Moldovan
Browse files
Fix application of keep_alive policy to constructors (regression)
parent
fbab29c7
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
53 additions
and
5 deletions
+53
-5
docs/advanced/functions.rst
docs/advanced/functions.rst
+11
-0
docs/changelog.rst
docs/changelog.rst
+6
-0
include/pybind11/cast.h
include/pybind11/cast.h
+3
-0
include/pybind11/pybind11.h
include/pybind11/pybind11.h
+12
-4
tests/test_call_policies.cpp
tests/test_call_policies.cpp
+2
-1
tests/test_call_policies.py
tests/test_call_policies.py
+19
-0
No files found.
docs/advanced/functions.rst
View file @
7939f4b3
...
@@ -191,6 +191,17 @@ container:
...
@@ -191,6 +191,17 @@ container:
py::class_<List>(m, "List")
py::class_<List>(m, "List")
.def("append", &List::append, py::keep_alive<1, 2>());
.def("append", &List::append, py::keep_alive<1, 2>());
For consistency, the argument indexing is identical for constructors. Index
``1`` still refers to the implicit ``this`` pointer, i.e. the object which is
being constructed. Index ``0`` refers to the return type which is presumed to
be ``void`` when a constructor is viewed like a function. The following example
ties the lifetime of the constructor element to the constructed object:
.. code-block:: cpp
py::class_<Nurse>(m, "Nurse")
.def(py::init<Patient &>(), py::keep_alive<1, 2>());
.. note::
.. note::
``keep_alive`` is analogous to the ``with_custodian_and_ward`` (if Nurse,
``keep_alive`` is analogous to the ``with_custodian_and_ward`` (if Nurse,
...
...
docs/changelog.rst
View file @
7939f4b3
...
@@ -11,6 +11,12 @@ v2.3.0 (Not yet released)
...
@@ -11,6 +11,12 @@ v2.3.0 (Not yet released)
* TBD
* TBD
v2.2.1 (Not yet released)
-----------------------------------------------------
* Fixed a regression where the ``py::keep_alive`` policy could not be applied
to constructors. `#1065 <https://github.com/pybind/pybind11/pull/1065>`_.
v2.2.0 (August 31, 2017)
v2.2.0 (August 31, 2017)
-----------------------------------------------------
-----------------------------------------------------
...
...
include/pybind11/cast.h
View file @
7939f4b3
...
@@ -1800,6 +1800,9 @@ struct function_call {
...
@@ -1800,6 +1800,9 @@ struct function_call {
/// The parent, if any
/// The parent, if any
handle
parent
;
handle
parent
;
/// If this is a call to an initializer, this argument contains `self`
handle
init_self
;
};
};
...
...
include/pybind11/pybind11.h
View file @
7939f4b3
...
@@ -511,6 +511,7 @@ protected:
...
@@ -511,6 +511,7 @@ protected:
if
(
self_value_and_holder
)
if
(
self_value_and_holder
)
self_value_and_holder
.
type
->
dealloc
(
self_value_and_holder
);
self_value_and_holder
.
type
->
dealloc
(
self_value_and_holder
);
call
.
init_self
=
PyTuple_GET_ITEM
(
args_in
,
0
);
call
.
args
.
push_back
(
reinterpret_cast
<
PyObject
*>
(
&
self_value_and_holder
));
call
.
args
.
push_back
(
reinterpret_cast
<
PyObject
*>
(
&
self_value_and_holder
));
call
.
args_convert
.
push_back
(
false
);
call
.
args_convert
.
push_back
(
false
);
++
args_copied
;
++
args_copied
;
...
@@ -1457,10 +1458,17 @@ inline void keep_alive_impl(handle nurse, handle patient) {
...
@@ -1457,10 +1458,17 @@ inline void keep_alive_impl(handle nurse, handle patient) {
}
}
PYBIND11_NOINLINE
inline
void
keep_alive_impl
(
size_t
Nurse
,
size_t
Patient
,
function_call
&
call
,
handle
ret
)
{
PYBIND11_NOINLINE
inline
void
keep_alive_impl
(
size_t
Nurse
,
size_t
Patient
,
function_call
&
call
,
handle
ret
)
{
keep_alive_impl
(
auto
get_arg
=
[
&
](
size_t
n
)
{
Nurse
==
0
?
ret
:
Nurse
<=
call
.
args
.
size
()
?
call
.
args
[
Nurse
-
1
]
:
handle
(),
if
(
n
==
0
)
Patient
==
0
?
ret
:
Patient
<=
call
.
args
.
size
()
?
call
.
args
[
Patient
-
1
]
:
handle
()
return
ret
;
);
else
if
(
n
==
1
&&
call
.
init_self
)
return
call
.
init_self
;
else
if
(
n
<=
call
.
args
.
size
())
return
call
.
args
[
n
-
1
];
return
handle
();
};
keep_alive_impl
(
get_arg
(
Nurse
),
get_arg
(
Patient
));
}
}
inline
std
::
pair
<
decltype
(
internals
::
registered_types_py
)
::
iterator
,
bool
>
all_type_info_get_cache
(
PyTypeObject
*
type
)
{
inline
std
::
pair
<
decltype
(
internals
::
registered_types_py
)
::
iterator
,
bool
>
all_type_info_get_cache
(
PyTypeObject
*
type
)
{
...
...
tests/test_call_policies.cpp
View file @
7939f4b3
...
@@ -32,7 +32,7 @@ bool DependentGuard::enabled = false;
...
@@ -32,7 +32,7 @@ bool DependentGuard::enabled = false;
TEST_SUBMODULE
(
call_policies
,
m
)
{
TEST_SUBMODULE
(
call_policies
,
m
)
{
// Parent/Child are used in:
// Parent/Child are used in:
// test_keep_alive_argument, test_keep_alive_return_value, test_alive_gc_derived,
// test_keep_alive_argument, test_keep_alive_return_value, test_alive_gc_derived,
// test_alive_gc_multi_derived, test_return_none
// test_alive_gc_multi_derived, test_return_none
, test_keep_alive_constructor
class
Child
{
class
Child
{
public:
public:
Child
()
{
py
::
print
(
"Allocating child."
);
}
Child
()
{
py
::
print
(
"Allocating child."
);
}
...
@@ -51,6 +51,7 @@ TEST_SUBMODULE(call_policies, m) {
...
@@ -51,6 +51,7 @@ TEST_SUBMODULE(call_policies, m) {
};
};
py
::
class_
<
Parent
>
(
m
,
"Parent"
)
py
::
class_
<
Parent
>
(
m
,
"Parent"
)
.
def
(
py
::
init
<>
())
.
def
(
py
::
init
<>
())
.
def
(
py
::
init
([](
Child
*
)
{
return
new
Parent
();
}),
py
::
keep_alive
<
1
,
2
>
())
.
def
(
"addChild"
,
&
Parent
::
addChild
)
.
def
(
"addChild"
,
&
Parent
::
addChild
)
.
def
(
"addChildKeepAlive"
,
&
Parent
::
addChild
,
py
::
keep_alive
<
1
,
2
>
())
.
def
(
"addChildKeepAlive"
,
&
Parent
::
addChild
,
py
::
keep_alive
<
1
,
2
>
())
.
def
(
"returnChild"
,
&
Parent
::
returnChild
)
.
def
(
"returnChild"
,
&
Parent
::
returnChild
)
...
...
tests/test_call_policies.py
View file @
7939f4b3
...
@@ -156,6 +156,25 @@ def test_return_none(capture):
...
@@ -156,6 +156,25 @@ def test_return_none(capture):
assert
capture
==
"Releasing parent."
assert
capture
==
"Releasing parent."
def
test_keep_alive_constructor
(
capture
):
n_inst
=
ConstructorStats
.
detail_reg_inst
()
with
capture
:
p
=
m
.
Parent
(
m
.
Child
())
assert
ConstructorStats
.
detail_reg_inst
()
==
n_inst
+
2
assert
capture
==
"""
Allocating child.
Allocating parent.
"""
with
capture
:
del
p
assert
ConstructorStats
.
detail_reg_inst
()
==
n_inst
assert
capture
==
"""
Releasing parent.
Releasing child.
"""
def
test_call_guard
():
def
test_call_guard
():
assert
m
.
unguarded_call
()
==
"unguarded"
assert
m
.
unguarded_call
()
==
"unguarded"
assert
m
.
guarded_call
()
==
"guarded"
assert
m
.
guarded_call
()
==
"guarded"
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment