1

I have a C++ class containing a (Poco) mutex:

class ClassWithMutex
{
    public:
                                ClassWithMutex();
        virtual                 ~ClassWithMutex();

        Poco::Mutex             mMyMutex;

    private:
        ClassWithMutex(const ClassWithMutex& );
        ClassWithMutex& operator=(const ClassWithMutex& other);

};

And another class, using it:

class ClassHavingAClassWithMutex
{
    public:
        ClassHavingAClassWithMutex();
        ~ClassHavingAClassWithMutex();
        ClassWithMutex      A;

    private:
        ClassHavingAClassWithMutex(const ClassHavingAClassWithMutex&);
        ClassHavingAClassWithMutex& ClassHavingAClassWithMutex::operator=(const ClassHavingAClassWithMutex& other);

};

When trying to create a wrapper for ClassHavingAClassWithMutex, I get an error:

Error   C2248   'ClassWithMutex::operator =': cannot access private member declared in class 'ClassWithMutex'   mvr C:\builds\vs2015\mvr\python_package\src\mvr\mvrPYTHON_wrap.cxx  6493    

where the Swig generated code looks like this:

SWIGINTERN PyObject *_wrap_ClassWithMutex_mMyMutex_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
  PyObject *resultobj = 0;
  ClassWithMutex *arg1 = (ClassWithMutex *) 0 ;
  void *argp1 = 0 ;
  int res1 = 0 ;
  PyObject *swig_obj[1] ;
  Poco::Mutex result;

  if (!args) SWIG_fail;
  swig_obj[0] = args;
  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ClassWithMutex, 0 |  0 );
  if (!SWIG_IsOK(res1)) {
    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ClassWithMutex_mMyMutex_get" "', argument " "1"" of type '" "ClassWithMutex *""'"); 
  }
  arg1 = reinterpret_cast< ClassWithMutex * >(argp1);
  {
    SWIG_PYTHON_THREAD_BEGIN_ALLOW;
    result =  ((arg1)->mMyMutex);
    SWIG_PYTHON_THREAD_END_ALLOW;
  }
  resultobj = SWIG_NewPointerObj((new Poco::Mutex(static_cast< const Poco::Mutex& >(result))), SWIGTYPE_p_Poco__Mutex, SWIG_POINTER_OWN |  0 );
  return resultobj;
fail:
  return NULL;
}

and errors emitted from this line:

if (arg1) (arg1)->A = *arg2;
and
resultobj = SWIG_NewPointerObj((new Poco::Mutex(static_cast< const Poco::Mutex& >(result))), SWIGTYPE_p_Poco__Mutex, SWIG_POINTER_OWN |  0 );

Swig interface file:

%immutable
%include "aiClassWithMutex.h"
%include "ClassHavingAClassWithMutex.h"
%mutable

Any suggestions on how to properly wrap the classes above with Swig? I made the copy and assignment ctor's private in the classes above, in order to prevent any copying, but it seems swig insist on it?

Totte Karlsson
  • 1,261
  • 1
  • 20
  • 55

1 Answers1

0

That's not caused by the copy constructor but the property setter (b/c A is public). As discussed in the comments, one option is to hide it, by adding:

%ignore ClassWithMutex::mMyMutex;

before the %include "aiClassWithMutex.h" in the .i file.

Also as discussed, SWIG resorts to copying when making mMyMutex immutable. AFAICT, there's no way around that other than writing a typemap and misusing the optimal setting (to prevent the construction of a temporary in the first place). With that, a functional .i file looks like:

%module mut

%{  
#include "aiClassWithMutex.h"
#include "ClassHavingAClassWithMutex.h"
%}      

%feature("immutable", 1) ClassWithMutex::mMyMutex;
%typemap(out, optimal="1") Poco::Mutex %{
  $result = SWIG_NewPointerObj(($1_ltype*)&$1, $&1_descriptor, 0);
%}      
%include "aiClassWithMutex.h"
%include "ClassHavingAClassWithMutex.h"
Wim Lavrijsen
  • 3,453
  • 1
  • 9
  • 21
  • Added .i code to the post, but that did not fix it..? – Totte Karlsson Nov 25 '19 at 00:30
  • Works for me ... which version of SWIG do you have? (I'm asking b/c I just noticed that for SWIG4 `readonly` is now `immutable` and it seems not to generate the A_set at all, since it won't compile.) – Wim Lavrijsen Nov 25 '19 at 00:40
  • I'm using Swig 4. I did try the immutable/mutable and now I'm getting the error in the 'getter' instead. I updated the post. – Totte Karlsson Nov 25 '19 at 00:43
  • I see .. as it's copying by value from the getter. Do you want access to the mutex? Ie. should the variable be hidden completely or accessed by pointer in the proxy? Actually, let me dig out both and fix the answer. – Wim Lavrijsen Nov 25 '19 at 01:09
  • I think it should be hidden, for now. – Totte Karlsson Nov 25 '19 at 01:15
  • Edited the answer. I'm still curious as to why SWIG insists on the copy, though. My guess is that's only b/c it guarantees the data member is truly `immutable` (i.e. also `const` as well, as calling any it its member functions will have no effect on the original data member). – Wim Lavrijsen Nov 25 '19 at 01:23
  • The codebase I'm currently sunk elbows-deep in (replacing mutexes from a third-party library with `std::recursive_mutex`, primarily) solved this by declaring a _pointer_ to the mutex as a class member, and creating the actual mutex in the constructor. (With `new`; it's then `delete`d in the destructor, of course). The mutex is locked with `const std::lock_guard guard(*mutex);` (Well... it is since I've replaced the third-party calls. But they were equivalent.) – FeRD Oct 23 '20 at 07:00
  • Somewhat to my surprise, this **_seems_** to work just fine, both with the original third-party mutexes and with `recursive_mutex`. And it makes our SWIG bindings compile happily, instead of producing this exact error. But I won't deny it makes me nervous. Is there a chance this is actually OK, or is it a time bomb? – FeRD Oct 23 '20 at 07:00
  • 1
    With a pointer data member, there is no copy by SWIG, so the issue above wouldn't show up. (In fact, it is what the typemap workaround relies on.) So yes, AFAICT, there should not be any problems in your case. – Wim Lavrijsen Oct 23 '20 at 16:47