Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
pybind11
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open
pybind11
Commits
7939f4b3
Commit
7939f4b3
authored
Sep 04, 2017
by
Dean Moldovan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix application of keep_alive policy to constructors (regression)
parent
fbab29c7
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
53 additions
and
5 deletions
+53
-5
docs/advanced/functions.rst
+11
-0
docs/changelog.rst
+6
-0
include/pybind11/cast.h
+3
-0
include/pybind11/pybind11.h
+12
-4
tests/test_call_policies.cpp
+2
-1
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