1

我正在尝试为 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())

谢谢您的帮助!

4

2 回答 2

1

此类型std::string &&映射使用一个临时值,该临时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"
于 2020-06-05T11:51:52.197 回答
0

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);
}

无需创建本地 var(归功于 S. Holtermann!)

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

%typemap(in) std::string && (std::string *temp){
   int res = SWIG_AsPtr_std_string($input, &temp);
   $1 = temp;
}
  • 作品
  • 尚未经过广泛测试
  • 它会导致内存泄漏吗?
于 2020-06-05T09:45:44.373 回答