【问题标题】:Python SWIG wrapper for C++ rvalue std::string &&用于 C++ 右值 std::string && 的 Python SWIG 包装器
【发布时间】:2020-09-19 00:28:31
【问题描述】:

我正在尝试为 gnucash c++ 部件构建一个 python 包装器。在QofBackend 遇到了方法const std::string && get_message ()。在 python 中,此消息返回 <Swig Object of type 'std::string *' at 0x7f4a20f5c9f0> 而不是我设置中的字符串,因为 std::string 右值引用没有 swig 类型映射。

我并没有真正找到一个简单的解释,所以我重新构建了一个示例设置并深入研究了我几乎不知道的 c++。我设法将字符串输入 python 但我想知道

  • 如果这种 typemap(out) 方法是正确的(同样在内存和错误处理方面)。
  • set_s_workaround() 中的转换也只是一种解决方法。我认为对于 gnucash,python 代码不需要设置这个值,但为了完整起见,最好还有一个 typemap(in) std::string&&
  • 摆脱get_s_workaround
  • 让 init_s_2 工作。
/* example.hpp */
#include <string>

using namespace std;

struct struct1{
        string s;
        const std::string&& get_s();
        void set_s(string&&);
        void set_s_workaround(string);
        void init_s();
        void init_s_2();
        void print_s();
};

string conv_rvalue_string(string);
/* example.cpp */
#include<iostream> 
#include"example.hpp"

using namespace std; 

void
struct1::set_s (std::string&& msg)
{
     s = msg;
}

std::string
conv_rvalue_string (std::string msg)
{
        return msg;
}

void
struct1::set_s_workaround(std::string msg)
{
        set_s ( conv_rvalue_string(msg) );
}

void
struct1::init_s ()
{
     set_s("Some content");
}

void
struct1::init_s_2()
{
     std::string msg {"Couldn't find "};
     /* set_s( msg ); */
}

void
struct1::print_s ()
{
     cout<<get_s()<<endl;
}

const std::string&&
struct1::get_s ()
{
    return std::move(s);
}
/* example.i */
%module example

%include "std_string.i"

%typemap(out) std::string&& {
  std::string s = *$1;
  $result = SWIG_From_std_string(s);
}


%{
#include <string>
#include "example.hpp"
%}

%include "example.hpp"
#!/bin/bash
swig3.0 -c++ -shadow -python example.i
g++ -fpic -c example.hpp example.cpp example_wrap.cxx -I/usr/include/python3.7
g++ -shared example_wrap.o example.o -o _example.so 
# pyexample.py
import example

s1 = example.struct1()
s1.set_s_workaround('TEST')
s1.print_s()
print(s1.get_s())

感谢您的帮助!

【问题讨论】:

    标签: python c++11 swig gnucash


    【解决方案1】:

    这个std::string &amp;&amp; 类型映射使用一个临时的std::string,它被传递给采用std::string 右值引用的方法。
    %typemap 中的片段依赖确保使用的片段在包装文件中已准备好。我们只是使用"std_string.i"已经提供的片段。

    /* example.i */
    %module example
    
    %include "std_string.i"
    
    %typemap(out, fragment="SWIG_From_std_string") std::string&& {
      $result = SWIG_From_std_string(*$1);
    }
    
    %typemap(in, fragment="SWIG_AsVal_std_string") std::string&& (std::string temp) {
      int res = SWIG_AsVal_std_string($input, &temp);
      $1 = &temp;
    }
    
    %{
    #include <string>
    #include "example.hpp"
    %}
    
    %include "example.hpp"
    

    【讨论】:

      【解决方案2】:

      init_s2() 会这样工作:

      void
      struct1::init_s_2()
      {
           std::string msg {"Couldn't find "};
           set_s( msg + "");
      }
      

      感谢 S. Holtermann!

      %typemap(out) std::string&& {
        std::string s = *$1;
        $result = SWIG_From_std_string(s);
      }
      

      可以缩短为

      %typemap(out) std::string&& {
        $result = SWIG_From_std_string(*$1);
      }
      

      不创建本地变量(感谢 S. Holtermann!)

      一个可能的 typemap(in) 可能是

      %typemap(in) std::string && (std::string *temp){
         int res = SWIG_AsPtr_std_string($input, &temp);
         $1 = temp;
      }
      
      • 作品
      • 尚未经过广泛测试
      • 会导致内存泄漏吗?

      【讨论】:

      • 这会泄露分配的临时字符串。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-31
      • 1970-01-01
      • 1970-01-01
      • 2020-07-14
      • 2021-08-29
      相关资源
      最近更新 更多