Search code examples
pythonc++smart-pointerscppyy

cppyy inherit class that contains a smart pointer


Here is a simple example of inheriting from a class that contains a smart pointer. We don't do anything with it, just declare it.

import cppyy

cppyy.cppdef("""
  class Example { 
   private:
    std::unique_ptr<double> x;
   public:
    Example() {}
    virtual ~Example() = default;
    double y = 66.;
   };
  """)

class Inherit(cppyy.gbl.Example):
    pass

 a = Inherit()
 print(a.y)  # Test whether this attribute was inherited

The example runs, but with a error about the smart pointer

input_line_19:9:43: error: call to implicitly-deleted copy constructor of '::Example'
  Dispatcher1(const Dispatcher1& other) : Example(other), m_self(other.m_self, this) {}
                                          ^       ~~~~~
input_line_17:4:29: note: copy constructor of 'Example' is implicitly deleted because field 'x' has a deleted copy constructor
    std::unique_ptr<double> x;
                            ^
/usr/include/c++/7/bits/unique_ptr.h:383:7: note: 'unique_ptr' has been explicitly marked deleted here
      unique_ptr(const unique_ptr&) = delete;
      ^
smart_ptr.py:14: RuntimeWarning: no python-side overrides supported
  class Inherit(cppyy.gbl.Example):
66.0

It nevertheless appears that the inheritance worked as we can still access the public variable from the C++ class. Actually, I'm not 100% sure whether cppyy is at fault here. Although the C++ seems alright, I may be using smart pointers/the virtual destructor in a strange way, as I'm not that experienced with smart pointers.

The error is not raised if I use a std::shared_ptr instead of a std::unique_ptr


Solution

  • As hinted by S.M., if we must use unique_ptr, the trick appears to be to make sure to define a copy constructor, e.g., this example gives the expected results with no error messages,

    import cppyy
    
    cppyy.cppdef("""
      class Example { 
        std::unique_ptr<double> x;
       public:
        Example() { x = std::unique_ptr<double>(new double(123.)); } 
        // Copy constructor
        Example(const Example& other) : x(other.x ? nullptr : new double(*other.x)) {}
        virtual ~Example() = default;
        double y = 66.;
        double get_x() { return *x; }
      };
      auto e = Example();
      auto f = e;
      """)
    
    class Inherit(cppyy.gbl.Example):
      pass
    
    a = Inherit()
    print(a.get_x())  # prints 123.
    print(a.y)  # prints 66.