2

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

innisfree
  • 2,044
  • 1
  • 14
  • 24
  • 2
    Define the custom copy constructor for Example. – 273K May 13 '20 at 00:24
  • @S.M. ah got it, would this problem occur in C++ anyway if I tried to inherit from the Example class? or is in actually a cppyy quirk? – innisfree May 13 '20 at 00:51
  • It's a problem with upstream: since the dispatcher adds a data member (the Python object to dispatch to), cppyy needs to customize the copy constructor if one is provided. It collects all constructors from upstream, which provides it with a copy constructor declaration even as it shouldn't, so cppyy "sees" a copy constructor and provides the custom implementation. Then fails the JIT. – Wim Lavrijsen May 13 '20 at 00:57
  • Filed a bug report: https://bitbucket.org/wlav/cppyy/issues/234/do-not-generate-a-copy-constructor-in – Wim Lavrijsen May 13 '20 at 01:01

1 Answers1

1

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.
innisfree
  • 2,044
  • 1
  • 14
  • 24
  • 1
    I'd check `x` before dereferencing, as in `Example(const Example& other) : x(other.x ? nullptr : new double(*other.x)) { }` – Wim Lavrijsen May 13 '20 at 00:58