我有同样的问题,想要一个不涉及 shared_ptr 的解决方案。它涉及专门一些 boost::python 类,以确保我们获得足够大的存储区域以能够在其中对齐我们的对象。
我写了一篇有点长的博客文章,解释了我是如何在这里找到这个解决方案的。以下是我找到的解决方案。我觉得这是一个相当黑客,所以也许它会破坏其他东西。但到目前为止,它似乎有效,我还没有发现更好的东西。
我试图公开一个 Eigen::Quaternionf (需要 16 个字节对齐):
bp::class_<Quaternionf>("Quaternion", bp::init<float, float, float, float>())
.def(bp::init<Matrix3f>())
.add_property("w", get_prop_const(&Quaternionf::w))
.add_property("x", get_prop_const(&Quaternionf::x))
.add_property("y", get_prop_const(&Quaternionf::y))
.add_property("z", get_prop_const(&Quaternionf::z))
.def("matrix", &Quaternionf::matrix)
.def("rotvec", &quaternion_to_rotvec);
该解决方案涉及专业化 3 类:
boost::python::objects::instance请求比我们的类型需要的多 16 个字节,以确保我们可以对齐
...
union
{
align_t align;
char bytes[sizeof(Data) + 16];
} storage;
...
boost::python::objects::make_instance_impl正确设置我们实例的 Py_SIZE
...
Holder* holder = Derived::construct(
&instance->storage, (PyObject*)instance, x);
holder->install(raw_result);
// Note the position of the internally-stored Holder,
// for the sake of destruction
// Since the holder not necessarily allocated at the start of
// storage (to respect alignment), we have to add the holder
// offset relative to storage
size_t holder_offset = reinterpret_cast<size_t>(holder)
- reinterpret_cast<size_t>(&instance->storage)
+ offsetof(instance_t, storage);
Py_SIZE(instance) = holder_offset;
...
boost::python::objects::make_instance以便构造方法将对齐存储中的持有者
...
static inline QuaternionfHolder* construct(void* storage, PyObject* instance, reference_wrapper<Quaternionf const> x)
{
// From the specialized make_instance_impl above, we are guaranteed to
// be able to align our storage
void* aligned_storage = reinterpret_cast<void*>(
(reinterpret_cast<size_t>(storage) & ~(size_t(15))) + 16);
QuaternionfHolder* new_holder = new (aligned_storage)
QuaternionfHolder(instance, x);
return new_holder;
}
...
完整代码如下:
typedef bp::objects::value_holder<Eigen::Quaternionf> QuaternionfHolder;
namespace boost { namespace python { namespace objects {
using namespace Eigen;
//template <class Data = char>
template<>
struct instance<QuaternionfHolder>
{
typedef QuaternionfHolder Data;
PyObject_VAR_HEAD
PyObject* dict;
PyObject* weakrefs;
instance_holder* objects;
typedef typename type_with_alignment<
::boost::alignment_of<Data>::value
>::type align_t;
union
{
align_t align;
char bytes[sizeof(Data) + 16];
} storage;
};
// Adapted from boost/python/object/make_instance.hpp
//template <class T, class Holder, class Derived>
template<class Derived>
struct make_instance_impl<Quaternionf, QuaternionfHolder, Derived>
{
typedef Quaternionf T;
typedef QuaternionfHolder Holder;
typedef objects::instance<Holder> instance_t;
template <class Arg>
static inline PyObject* execute(Arg& x)
{
BOOST_MPL_ASSERT((mpl::or_<is_class<T>, is_union<T> >));
PyTypeObject* type = Derived::get_class_object(x);
if (type == 0)
return python::detail::none();
PyObject* raw_result = type->tp_alloc(
type, objects::additional_instance_size<Holder>::value);
if (raw_result != 0)
{
python::detail::decref_guard protect(raw_result);
instance_t* instance = (instance_t*)raw_result;
// construct the new C++ object and install the pointer
// in the Python object.
//Derived::construct(&instance->storage, (PyObject*)instance, x)->install(raw_result);
Holder* holder = Derived::construct(
&instance->storage, (PyObject*)instance, x);
holder->install(raw_result);
// Note the position of the internally-stored Holder,
// for the sake of destruction
// Since the holder not necessarily allocated at the start of
// storage (to respect alignment), we have to add the holder
// offset relative to storage
size_t holder_offset = reinterpret_cast<size_t>(holder)
- reinterpret_cast<size_t>(&instance->storage)
+ offsetof(instance_t, storage);
Py_SIZE(instance) = holder_offset;
// Release ownership of the python object
protect.cancel();
}
return raw_result;
}
};
//template <class T, class Holder>
template<>
struct make_instance<Quaternionf, QuaternionfHolder>
: make_instance_impl<Quaternionf, QuaternionfHolder, make_instance<Quaternionf,QuaternionfHolder> >
{
template <class U>
static inline PyTypeObject* get_class_object(U&)
{
return converter::registered<Quaternionf>::converters.get_class_object();
}
static inline QuaternionfHolder* construct(void* storage, PyObject* instance, reference_wrapper<Quaternionf const> x)
{
LOG(INFO) << "Into make_instance";
LOG(INFO) << "storage : " << storage;
LOG(INFO) << "&x : " << x.get_pointer();
LOG(INFO) << "&x alignment (0 = aligned): " << (reinterpret_cast<size_t>(x.get_pointer()) & 0xf);
// From the specialized make_instance_impl above, we are guaranteed to
// be able to align our storage
void* aligned_storage = reinterpret_cast<void*>(
(reinterpret_cast<size_t>(storage) & ~(size_t(15))) + 16);
QuaternionfHolder* new_holder = new (aligned_storage) QuaternionfHolder(instance, x);
LOG(INFO) << "&new_holder : " << new_holder;
return new_holder;
//return new (storage) QuaternionfHolder(instance, x);
}
};
}}} // namespace boost::python::objects