How to use weak_ptr in swig?

2019-02-14 18:37发布

问题:

SWIG homepage says shared_ptr is specially handled, but weak_ptr not. Does it means weak_ptr supporting has some bug/issue in SWIG? If it's ok to use, how to use it? Can anybody please give a sample .i code? Thanks very much.

回答1:

weak_ptr doesn't need any special support in SWIG to use.

The operations that need special support in SWIG for shared_ptr are dereferencing and passing into functions. This is because you never directly dereference or create a weak_ptr. Instead when you're using it normally in C++ you would call the lock() member function to upgrade it to a full, retained shared_ptr or one of the other functions to query its state.

So all you need to do in practice therefore is wrap weak_ptr like any other template and use the existing shared_ptr support in conjunction. For example:

%module test

%{
#include <memory>
%}

%include <std_shared_ptr.i>

%shared_ptr(Foo)

namespace std {
template<class Ty> class weak_ptr {
public:
    typedef Ty element_type;

    weak_ptr();
    weak_ptr(const weak_ptr&);
    template<class Other>
        weak_ptr(const weak_ptr<Other>&);
    template<class Other>
        weak_ptr(const shared_ptr<Other>&);

    weak_ptr(const shared_ptr<Ty>&);


    void swap(weak_ptr&);
    void reset();

    long use_count() const;
    bool expired() const;
    shared_ptr<Ty> lock() const;
};
}

%inline %{
    struct Foo { };
%}
%template(FooWeakPtr) std::weak_ptr<Foo>;

This can be exercised with some Java:

public class run {
  public static void main(String[] argv) {
    System.loadLibrary("test");

    Foo a = new Foo();
    System.out.println(a);

    FooWeakPtr b=new FooWeakPtr(a);
    System.out.println(b);

    Foo c=b.lock();
    System.out.println(c);

    System.out.println(b.use_count());
    a=null;
    System.gc();
    System.out.println(b.use_count());
    c=null;
    System.gc();
    System.out.println(b.use_count());

    Foo d=b.lock();
    System.out.println(d);
  }
}

When run this gives:

swig2.0 -c++ -Wall -java test.i && g++ -Wall -Wextra -I/usr/lib/jvm/java-6-sun/include -I/usr/lib/jvm/java-6-sun/include/linux -std=c++0x -shared -o libtest.so test_wrap.cxx && javac run.java && LD_LIBRARY_PATH=. java run
Foo@42719c
FooWeakPtr@119298d
Foo@f72617
2
2
2
Foo@dc8569

(Notice here that System.gc() has been completely ignored by my runtime, so the attempt to lock again does actually succeed)

But it also works with the same .i file for the following Python:

import test

a=test.Foo()
print a

b=test.FooWeakPtr(a)
print b

c=b.lock()
print c

print b.use_count()
a=None
print b.use_count()
c=None
print b.use_count()

d=b.lock()
print d

And when run gives:

g++ -Wall -Wextra -I/usr/include/python2.6 -std=c++0x -shared -o _test.so test_wrap.cxx && python run.py
<test.Foo; proxy of <Swig Object of type 'std::shared_ptr< Foo > *' at 0xf7419710> >
<test.FooWeakPtr; proxy of <Swig Object of type 'std::weak_ptr< Foo > *' at 0xf7419728> >
<test.Foo; proxy of <Swig Object of type 'std::shared_ptr< Foo > *' at 0xf7419740> >
2
1
0
None

Where the reference counting instead of GC does result in the call to lock() failing after the last shared_ptr has no more references.