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
e3cb2a67
Commit
e3cb2a67
authored
Jun 20, 2018
by
Khachajantc Michael
Committed by
Jason Rhinelander
Jun 23, 2018
Browse files
Use std::addressof to obtain holder address instead of operator&
parent
9b028562
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
115 additions
and
7 deletions
+115
-7
include/pybind11/cast.h
include/pybind11/cast.h
+2
-2
include/pybind11/pybind11.h
include/pybind11/pybind11.h
+5
-5
tests/test_smart_ptr.cpp
tests/test_smart_ptr.cpp
+64
-0
tests/test_smart_ptr.py
tests/test_smart_ptr.py
+44
-0
No files found.
include/pybind11/cast.h
View file @
e3cb2a67
...
...
@@ -1423,7 +1423,7 @@ public:
explicit
operator
type
*
()
{
return
this
->
value
;
}
explicit
operator
type
&
()
{
return
*
(
this
->
value
);
}
explicit
operator
holder_type
*
()
{
return
&
holder
;
}
explicit
operator
holder_type
*
()
{
return
std
::
addressof
(
holder
)
;
}
// Workaround for Intel compiler bug
// see pybind11 issue 94
...
...
@@ -1493,7 +1493,7 @@ struct move_only_holder_caster {
static
handle
cast
(
holder_type
&&
src
,
return_value_policy
,
handle
)
{
auto
*
ptr
=
holder_helper
<
holder_type
>::
get
(
src
);
return
type_caster_base
<
type
>::
cast_holder
(
ptr
,
&
src
);
return
type_caster_base
<
type
>::
cast_holder
(
ptr
,
std
::
addressof
(
src
)
)
;
}
static
constexpr
auto
name
=
type_caster_base
<
type
>::
name
;
};
...
...
include/pybind11/pybind11.h
View file @
e3cb2a67
...
...
@@ -1271,25 +1271,25 @@ private:
auto
sh
=
std
::
dynamic_pointer_cast
<
typename
holder_type
::
element_type
>
(
v_h
.
value_ptr
<
type
>
()
->
shared_from_this
());
if
(
sh
)
{
new
(
&
v_h
.
holder
<
holder_type
>
())
holder_type
(
std
::
move
(
sh
));
new
(
std
::
addressof
(
v_h
.
holder
<
holder_type
>
())
)
holder_type
(
std
::
move
(
sh
));
v_h
.
set_holder_constructed
();
}
}
catch
(
const
std
::
bad_weak_ptr
&
)
{}
if
(
!
v_h
.
holder_constructed
()
&&
inst
->
owned
)
{
new
(
&
v_h
.
holder
<
holder_type
>
())
holder_type
(
v_h
.
value_ptr
<
type
>
());
new
(
std
::
addressof
(
v_h
.
holder
<
holder_type
>
())
)
holder_type
(
v_h
.
value_ptr
<
type
>
());
v_h
.
set_holder_constructed
();
}
}
static
void
init_holder_from_existing
(
const
detail
::
value_and_holder
&
v_h
,
const
holder_type
*
holder_ptr
,
std
::
true_type
/*is_copy_constructible*/
)
{
new
(
&
v_h
.
holder
<
holder_type
>
())
holder_type
(
*
reinterpret_cast
<
const
holder_type
*>
(
holder_ptr
));
new
(
std
::
addressof
(
v_h
.
holder
<
holder_type
>
())
)
holder_type
(
*
reinterpret_cast
<
const
holder_type
*>
(
holder_ptr
));
}
static
void
init_holder_from_existing
(
const
detail
::
value_and_holder
&
v_h
,
const
holder_type
*
holder_ptr
,
std
::
false_type
/*is_copy_constructible*/
)
{
new
(
&
v_h
.
holder
<
holder_type
>
())
holder_type
(
std
::
move
(
*
const_cast
<
holder_type
*>
(
holder_ptr
)));
new
(
std
::
addressof
(
v_h
.
holder
<
holder_type
>
())
)
holder_type
(
std
::
move
(
*
const_cast
<
holder_type
*>
(
holder_ptr
)));
}
/// Initialize holder object, variant 2: try to construct from existing holder object, if possible
...
...
@@ -1299,7 +1299,7 @@ private:
init_holder_from_existing
(
v_h
,
holder_ptr
,
std
::
is_copy_constructible
<
holder_type
>
());
v_h
.
set_holder_constructed
();
}
else
if
(
inst
->
owned
||
detail
::
always_construct_holder
<
holder_type
>::
value
)
{
new
(
&
v_h
.
holder
<
holder_type
>
())
holder_type
(
v_h
.
value_ptr
<
type
>
());
new
(
std
::
addressof
(
v_h
.
holder
<
holder_type
>
())
)
holder_type
(
v_h
.
value_ptr
<
type
>
());
v_h
.
set_holder_constructed
();
}
}
...
...
tests/test_smart_ptr.cpp
View file @
e3cb2a67
...
...
@@ -55,6 +55,35 @@ public:
};
PYBIND11_DECLARE_HOLDER_TYPE
(
T
,
custom_unique_ptr
<
T
>
);
// Simple custom holder that works like shared_ptr and has operator& overload
// To obtain address of an instance of this holder pybind should use std::addressof
// Attempt to get address via operator& may leads to segmentation fault
template
<
typename
T
>
class
shared_ptr_with_addressof_operator
{
std
::
shared_ptr
<
T
>
impl
;
public:
shared_ptr_with_addressof_operator
(
)
=
default
;
shared_ptr_with_addressof_operator
(
T
*
p
)
:
impl
(
p
)
{
}
T
*
get
()
const
{
return
impl
.
get
();
}
T
**
operator
&
()
{
throw
std
::
logic_error
(
"Call of overloaded operator& is not expected"
);
}
};
PYBIND11_DECLARE_HOLDER_TYPE
(
T
,
shared_ptr_with_addressof_operator
<
T
>
);
// Simple custom holder that works like unique_ptr and has operator& overload
// To obtain address of an instance of this holder pybind should use std::addressof
// Attempt to get address via operator& may leads to segmentation fault
template
<
typename
T
>
class
unique_ptr_with_addressof_operator
{
std
::
unique_ptr
<
T
>
impl
;
public:
unique_ptr_with_addressof_operator
()
=
default
;
unique_ptr_with_addressof_operator
(
T
*
p
)
:
impl
(
p
)
{
}
T
*
get
()
const
{
return
impl
.
get
();
}
T
*
release_ptr
()
{
return
impl
.
release
();
}
T
**
operator
&
()
{
throw
std
::
logic_error
(
"Call of overloaded operator& is not expected"
);
}
};
PYBIND11_DECLARE_HOLDER_TYPE
(
T
,
unique_ptr_with_addressof_operator
<
T
>
);
TEST_SUBMODULE
(
smart_ptr
,
m
)
{
...
...
@@ -238,6 +267,41 @@ TEST_SUBMODULE(smart_ptr, m) {
py
::
class_
<
C
,
custom_unique_ptr
<
C
>>
(
m
,
"TypeWithMoveOnlyHolder"
)
.
def_static
(
"make"
,
[]()
{
return
custom_unique_ptr
<
C
>
(
new
C
);
});
// test_holder_with_addressof_operator
struct
TypeForHolderWithAddressOf
{
TypeForHolderWithAddressOf
()
{
print_created
(
this
);
}
TypeForHolderWithAddressOf
(
const
TypeForHolderWithAddressOf
&
)
{
print_copy_created
(
this
);
}
TypeForHolderWithAddressOf
(
TypeForHolderWithAddressOf
&&
)
{
print_move_created
(
this
);
}
~
TypeForHolderWithAddressOf
()
{
print_destroyed
(
this
);
}
std
::
string
toString
()
const
{
return
"TypeForHolderWithAddressOf["
+
std
::
to_string
(
value
)
+
"]"
;
}
int
value
=
42
;
};
using
HolderWithAddressOf
=
shared_ptr_with_addressof_operator
<
TypeForHolderWithAddressOf
>
;
py
::
class_
<
TypeForHolderWithAddressOf
,
HolderWithAddressOf
>
(
m
,
"TypeForHolderWithAddressOf"
)
.
def_static
(
"make"
,
[]()
{
return
HolderWithAddressOf
(
new
TypeForHolderWithAddressOf
);
})
.
def
(
"get"
,
[](
const
HolderWithAddressOf
&
self
)
{
return
self
.
get
();
})
.
def
(
"print_object_1"
,
[](
const
TypeForHolderWithAddressOf
*
obj
)
{
py
::
print
(
obj
->
toString
());
})
.
def
(
"print_object_2"
,
[](
HolderWithAddressOf
obj
)
{
py
::
print
(
obj
.
get
()
->
toString
());
})
.
def
(
"print_object_3"
,
[](
const
HolderWithAddressOf
&
obj
)
{
py
::
print
(
obj
.
get
()
->
toString
());
})
.
def
(
"print_object_4"
,
[](
const
HolderWithAddressOf
*
obj
)
{
py
::
print
((
*
obj
).
get
()
->
toString
());
});
// test_move_only_holder_with_addressof_operator
struct
TypeForMoveOnlyHolderWithAddressOf
{
TypeForMoveOnlyHolderWithAddressOf
(
int
value
)
:
value
{
value
}
{
print_created
(
this
);
}
~
TypeForMoveOnlyHolderWithAddressOf
()
{
print_destroyed
(
this
);
}
std
::
string
toString
()
const
{
return
"MoveOnlyHolderWithAddressOf["
+
std
::
to_string
(
value
)
+
"]"
;
}
int
value
;
};
using
MoveOnlyHolderWithAddressOf
=
unique_ptr_with_addressof_operator
<
TypeForMoveOnlyHolderWithAddressOf
>
;
py
::
class_
<
TypeForMoveOnlyHolderWithAddressOf
,
MoveOnlyHolderWithAddressOf
>
(
m
,
"TypeForMoveOnlyHolderWithAddressOf"
)
.
def_static
(
"make"
,
[]()
{
return
MoveOnlyHolderWithAddressOf
(
new
TypeForMoveOnlyHolderWithAddressOf
(
0
));
})
.
def_readwrite
(
"value"
,
&
TypeForMoveOnlyHolderWithAddressOf
::
value
)
.
def
(
"print_object"
,
[](
const
TypeForMoveOnlyHolderWithAddressOf
*
obj
)
{
py
::
print
(
obj
->
toString
());
});
// test_smart_ptr_from_default
struct
HeldByDefaultHolder
{
};
py
::
class_
<
HeldByDefaultHolder
>
(
m
,
"HeldByDefaultHolder"
)
...
...
tests/test_smart_ptr.py
View file @
e3cb2a67
...
...
@@ -203,6 +203,50 @@ def test_move_only_holder():
assert
stats
.
alive
()
==
0
def
test_holder_with_addressof_operator
():
# this test must not throw exception from c++
a
=
m
.
TypeForHolderWithAddressOf
.
make
()
a
.
print_object_1
()
a
.
print_object_2
()
a
.
print_object_3
()
a
.
print_object_4
()
stats
=
ConstructorStats
.
get
(
m
.
TypeForHolderWithAddressOf
)
assert
stats
.
alive
()
==
1
np
=
m
.
TypeForHolderWithAddressOf
.
make
()
assert
stats
.
alive
()
==
2
del
a
assert
stats
.
alive
()
==
1
del
np
assert
stats
.
alive
()
==
0
b
=
m
.
TypeForHolderWithAddressOf
.
make
()
c
=
b
assert
b
.
get
()
is
c
.
get
()
assert
stats
.
alive
()
==
1
del
b
assert
stats
.
alive
()
==
1
del
c
assert
stats
.
alive
()
==
0
def
test_move_only_holder_with_addressof_operator
():
a
=
m
.
TypeForMoveOnlyHolderWithAddressOf
.
make
()
a
.
print_object
()
stats
=
ConstructorStats
.
get
(
m
.
TypeForMoveOnlyHolderWithAddressOf
)
assert
stats
.
alive
()
==
1
a
.
value
=
42
assert
a
.
value
==
42
del
a
assert
stats
.
alive
()
==
0
def
test_smart_ptr_from_default
():
instance
=
m
.
HeldByDefaultHolder
()
with
pytest
.
raises
(
RuntimeError
)
as
excinfo
:
...
...
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