简体   繁体   中英

SWIG: template return from python gives "memory leak no destructor found" warning

I have some python functions which I run from C++ side and I need them to return std::expected objects. What I did is this:

def do_operation(self):
    print("Operation done")
    return void_expected()

In Swig code I have something like:

%inline %{
    std::expected<void, OperationError> void_expected()
    {
        return std::expected<void, OperationError>{};
    }
%}

%typemap(out) std::expected<void, OperationError> {
    if (!$1.has_value()) {
        SWIG_exception(SWIG_RuntimeError, "Unexpected error!");
    }
    Py_RETURN_NONE;
}

But I am getting all these warnings running the python script:

swig/python detected a memory leak of type 'std::expected< void,OperationError > *', no destructor found.

The error message you're seeing hints towards what's going on. Although my older answer on that warning does apply here it shouldn't and that hints as to what's gone wrong. Your expected behaviour is that for the case where a value is returned in C++ None is return in Python. Conversely if there isn't a value in the expected object then a Python exception is raised. In neither case are you expecting SWIG to create a Proxy object on the Python side for the std::expected result.

So the fact that you've seen this warning indicate that something's not as expected in your interface as written. And it turns out to be fairly simple - the typemap you showed comes after the place where it's expected to be used. So it doesn't get applied.

We can confirm this by constructing a small, complete example:

%module test

%include <exception.i>

%{
#include "expected.h" // TODO: include <expected>  insteadwhen I really have C++23 impl 
%}


%typemap(out) std::expected<void, OperationError> {
    if (!$1.has_value()) {
        SWIG_exception(SWIG_RuntimeError, "Unexpected error!");
    }
    Py_RETURN_NONE;
}

%inline %{
        class OperationError {};
        std::expected<void, OperationError> void_expected() {
                return std::expected<void, OperationError>{};
        }
%}

(I had to make my own expected.h since I don't have a C++23 compiler to hand!)

// Minimal parts needed to prove the point with this answer
namespace std {
        template <typename T, typename E>
        struct expected {
                bool has_value() const { return true; }
        };
}

And some Python to prove it:

import test

test.void_expected()

Which we can then build and run like this:

swig3.0 -c++ -python -py3 test.i
g++ -shared -Wall -Wextra test_wrap.cxx  -I/usr/include/python3.7 -m32 -o _test.so 
python3 run.py

This runs with no error. Swap the order of the typemap and the %inline with void_expected() declaration/definition around however as in your question and you'll see the exact same error since the typemap isn't getting applied.


The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM