Search code examples
pythonboostboost-python

Why boost python calls the copy constructor?


Assume a wrapper class is provided

class Example
{
public:
    Example()
    {
        std::cout << "hello\n";
    }
    Example(const Example& e)
    {
        std::cout << "copy\n";
        counter++;
    }
    ~Example()
    {
        std::cout << "bye\n";
    }
    Example& count()
    {
        std::cout << "Count: " << counter << std::endl;
        return *this;
    }
    static int counter;
};
int Example::counter = 0;

which is exposed to python using

using namespace boost::python;
class_<Example>("Example", init<>())
        .def("count", &Example::count, return_value_policy<copy_non_const_reference>());

now if i execute the following python code

obj=Example()
obj.count().count()

I get

hello
Count: 0
copy
Count: 1
copy
bye

which means boost python is using the copy constructor.

My questions:

  1. Why the copy constructor is called?
  2. If I use boost::noncopyable, then the copy constructor is not called. However, in this case I cannot execute my python code as it complains about a to_python converter (see below). Is there way to fix this?

    TypeError: No to_python (by-value) converter found for C++ type: class Example


Solution

  • The copy constructor is called because return_value_policy<copy_non_const_reference>() is being set and by boost docs:

    copy_non_const_reference is a model of ResultConverterGenerator which can be used to wrap C++ functions returning a reference-to-non-const type such that the referenced value is copied into a new Python object.

    It complains because the return value is required to be copied but at the same time the class is noncopyable so the default converter is not found.

    To fix this either don't use return_value_policy<copy_non_const_reference>() or define your custom to_python converter.