简体   繁体   中英

using unique_ptr with boost python - boost::shared_ptr works but unique_ptr doesnt

This may be the same issue as

Boost Python No to_python for std::unique_ptr

However, i haven't seen a response and it's not clear if this is a 'boost-python' issue or due to my particular use of 'std::unique_ptr' I'm trying to figure out why changing a class derived from boost::shared_ptr breaks compilation when using "std::unique_ptr []"

Below is my boost python module with 2 possible 'smart_array' classes The original is based on boost::shared_array and works fine (show below)

When I use one based on unique_ptr (simple substitution), I get confusing compile errors.

// Boost Includes ==============================================================
#include <boost/python.hpp>
#include <boost/cstdint.hpp>

#define NO_BOOST
#ifdef NO_BOOST
#include "smart_array.h"
#else
#include "boost_smart_array.h"
#endif
template <class Numeric> class cic {
public:
        smart_array<Numeric> nacc; //! Accumulators
        cic(int s) :  nacc(3) {
                for (int i=0;i<3;i++) nacc[i] = (Numeric)0;
        }
        Numeric interpolate() {         return(nacc[2]);        }
};

// Using =======================================================================
using namespace boost::python;
BOOST_PYTHON_MODULE(cic_double)
{
        class_< cic<double> >("cic_double", init< int >())
                .def("interpolate", &cic<double>::interpolate);
}

-- Smart array class (original - boost)

#include "boost/shared_array.hpp"
    template<class T> class smart_array : public boost::shared_array<T> {
    public:
            //! Default constructor
            smart_array() {} 
            //! Create an smart_array of size n
            smart_array(long n) : boost::shared_array<T>(new T[n]) {
                    elements = n;
            }
            void resize(long n) { 
                    elements = n;
                    boost::shared_array<T>::reset(new T[n]); 
            }
            long len() const { return(elements); }
    private:
            long elements;
    };

New - based on unique_ptr

template<class T> class smart_array : public std::unique_ptr<T []> {
 public:
  //! Default constructor
  smart_array() {} 
  //! Create an smart_array of size n
  smart_array(long n) : std::unique_ptr<T []>(new T[n]) {
                elements = n;
  }
  void resize(long n) { 
                elements = n;
                std::unique_ptr<T []>::reset(new T[n]); 
  }
  long len() const { return(elements); }
 private:
  long elements;
};

Compilation errors

[100%] Building CXX object CMakeFiles/cic_double.dir/py_cic_double.cpp.o
In file included from /Users/user/GitHubStuff/boost_cic_test/py_cic_double.cpp:2:
In file included from /usr/local/include/boost/python.hpp:18:
In file included from /usr/local/include/boost/python/class.hpp:23:
In file included from /usr/local/include/boost/python/object/class_metadata.hpp:11:
In file included from /usr/local/include/boost/python/object/value_holder.hpp:50:
In file included from /usr/local/include/boost/preprocessor/iteration/detail/iter/forward1.hpp:52:
/usr/local/include/boost/python/object/value_holder.hpp:135:11: error: no matching constructor for initialization of 'cic<double>'
        : m_held(
          ^
/usr/local/include/boost/python/object/make_instance.hpp:71:30: note: in instantiation of function template specialization 'boost::python::objects::value_holder<cic<double> >::value_holder<boost::reference_wrapper<const cic<double> > >' requested here
        return new (storage) Holder(instance, x);
                             ^
/usr/local/include/boost/python/object/make_instance.hpp:45:22: note: in instantiation of member function 'boost::python::objects::make_instance<cic<double>, boost::python::objects::value_holder<cic<double> > >::construct' requested here
            Derived::construct(&instance->storage, (PyObject*)instance, x)->install(raw_result);
                     ^
/usr/local/include/boost/python/object/class_wrapper.hpp:29:30: note: in instantiation of function template specialization 'boost::python::objects::make_instance_impl<cic<double>, boost::python::objects::value_holder<cic<double> >, boost::python::objects::make_instance<cic<double>, boost::python::objects::value_holder<cic<double> > > >::execute<const boost::reference_wrapper<const cic<double> > >' requested here
        return MakeInstance::execute(boost::ref(x));
                             ^
/usr/local/include/boost/python/converter/as_to_python_function.hpp:27:72: note: in instantiation of member function 'boost::python::objects::class_cref_wrapper<cic<double>, boost::python::objects::make_instance<cic<double>, boost::python::objects::value_holder<cic<double> > > >::convert' requested here
        convert_function_must_take_value_or_const_reference(&ToPython::convert, 1L);
                                                                       ^
/usr/local/include/boost/python/to_python_converter.hpp:88:22: note: in instantiation of member function 'boost::python::converter::as_to_python_function<cic<double>, boost::python::objects::class_cref_wrapper<cic<double>, boost::python::objects::make_instance<cic<double>, boost::python::objects::value_holder<cic<double> > > > >::convert' requested here
        &normalized::convert
                     ^
/usr/local/include/boost/python/object/class_wrapper.hpp:24:8: note: (skipping 2 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
struct class_cref_wrapper
       ^
/usr/local/include/boost/python/object/class_metadata.hpp:219:25: note: in instantiation of function template specialization 'boost::python::objects::class_metadata<cic<double>, boost::python::detail::not_specified, boost::python::detail::not_specified, boost::python::detail::not_specified>::register_aux2<cic<double>, boost::integral_constant<bool, false> >' requested here
        class_metadata::register_aux2((T*)0, use_callback());
                        ^
/usr/local/include/boost/python/object/class_metadata.hpp:205:25: note: in instantiation of member function 'boost::python::objects::class_metadata<cic<double>, boost::python::detail::not_specified, boost::python::detail::not_specified, boost::python::detail::not_specified>::register_aux' requested here
        class_metadata::register_aux((T*)0);
                        ^
/usr/local/include/boost/python/class.hpp:497:19: note: in instantiation of member function 'boost::python::objects::class_metadata<cic<double>, boost::python::detail::not_specified, boost::python::detail::not_specified, boost::python::detail::not_specified>::register_' requested here
        metadata::register_(); // set up runtime metadata/conversions
                  ^
/usr/local/include/boost/python/class.hpp:209:15: note: in instantiation of function template specialization 'boost::python::class_<cic<double>, boost::python::detail::not_specified, boost::python::detail::not_specified, boost::python::detail::not_specified>::initialize<boost::python::init_base<boost::python::init<int, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_> > >' requested here
        this->initialize(i);
              ^
/Users/user/GitHubStuff/boost_cic_test/py_cic_double.cpp:24:2: note: in instantiation of function template specialization 'boost::python::class_<cic<double>, boost::python::detail::not_specified, boost::python::detail::not_specified, boost::python::detail::not_specified>::class_<boost::python::init<int, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_, mpl_::void_> >' requested here
        class_< cic<double> >("cic_double", init< int >())
        ^
/Users/user/GitHubStuff/boost_cic_test/py_cic_double.cpp:11:32: note: candidate constructor (the implicit copy constructor) not viable: 1st argument ('typename reference_wrapper<const cic<double> >::type' (aka 'const cic<double>')) would lose const qualifier
template <class Numeric> class cic {
                               ^
/Users/user/GitHubStuff/boost_cic_test/py_cic_double.cpp:14:2: note: candidate constructor not viable: no known conversion from 'typename reference_wrapper<const cic<double> >::type' (aka 'const cic<double>') to 'int' for 1st argument
        cic(int s) :  nacc(3) {
        ^
1 error generated.
make[3]: *** [CMakeFiles/cic_double.dir/py_cic_double.cpp.o] Error 1
make[2]: *** [CMakeFiles/cic_double.dir/all] Error 2
make[1]: *** [all] Error 2
make: *** [all] Error 2

Unfortunately, at the moment, it is not possible to expose a std::unique_ptr using boost::python, as it requires move semantics, and these are not supported by boost::python yet (more details here ). Moreover, you should not derive from smart pointers, because it is not a good practice and they do not have virtual destructors (apart from many other reasons)

Saying that, you have quite a few other options, some of which are:

  • use std::auto_ptr as a data member, which is well supported by boost::python (assuming your class is made non-copyable). However, an auto_ptr cannot hold an array (it would not call the correct variant of delete() ).
  • use boost::shared_ptr as a data member, and hide its use in the API. However, please note that boost::shared_ptr cannot not hold array data either, for the same reason as above.
  • wrap an std::vector<boost::shared_ptr<>> , which will work with boost::shared_ptr out of the box using vector_indexing_suite .
  • ... and many others.

However, there are many other ways, and I would personally recommend to redesign your code to use some of the more generally accepted coding and python-wrapping practices from boost::python examples.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM