SWIG: избегайте псевдонимов C ++ до Python - PullRequest
0 голосов
/ 05 августа 2020

Я создаю библиотеку на C ++, которая связана с Python 3 с помощью SWIG 4.0.1. После некоторого времени разработки я заметил проблему с (как мне кажется) алиасингом. Я подготовил минимальный пример, который тоже случается.

Рассмотрим класс dummy с единственным (частным) атрибутом attr, который инициализируется как 0. Теперь у меня есть этот очень маленький python скрипт:

import dummy_wrap
d1 = dummy_wrap.dummy()
d2 = d1
d1.set_attr(12)
print(d2.get_attr()) # this prints '12', not '0'

Я надеюсь, что то, что я называю псевдонимом, действительно происходит здесь: объект d2 никогда не изменяется, но принимает значение, присвоенное d1, как если бы присвоение d2=d1 было назначением указателя. Я бы хотел (а также ожидаю), что оператор присваивания a=b делает бумажную копию b и передает ее на a. Другими словами, изменения в a не должны влиять на b и наоборот, если это соответствует деталям реализации (как в моей библиотеке и в минимальном примере).

В заключении обратите внимание, это сообщения, которые я получаю при компиляции:

g++ -fPIC -c dummy.cpp
g++ -fPIC -shared -o libdummy_lib.so dummy.o
swig -Wall -c++ -python -py3 -o dummy_wrap.cxx dummy_wrap.i
dummy.hpp:10: Warning 362: operator= ignored
dummy.hpp:11: Warning 362: operator= ignored
dummy.hpp:7: Warning 509: Overloaded method dummy::dummy(dummy &&) effectively ignored,
dummy.hpp:6: Warning 509: as it is shadowed by dummy::dummy(dummy const &).
g++ -fPIC -c dummy_wrap.cxx -I /usr/include/python3.8
g++ -fPIC -shared -o _dummy_wrap.so dummy_wrap.o -L . -ldummy_lib -lpython3.8

Вопросы:

  • Я хотел бы понять, что здесь происходит и почему: делать dummy(dummy&&) и dummy& operator=(dummy&&) влияют на то, как SWIG обертывает dummy(const dummy&) и dummy& operator=(const dummy&)?
  • Разумно ли ожидать того, что я хотел бы иметь по умолчанию, а именно, является ли это (псевдоним) ожидаемым поведение класса после взаимодействия с python с помощью SWIG?
  • Как я могу это исправить: какие изменения я должен внести, чтобы оператор = сделал бумажную копию?

Заранее большое спасибо.

Чтобы воспроизвести это, заголовок класса dummy.hpp имеет следующий вид:

#pragma once

class dummy {
    public:
        dummy() = default;
        dummy(const dummy&) = default;
        dummy(dummy&&) = default;
        ~dummy() = default;
        dummy& operator=(const dummy&) = default;
        dummy& operator=(dummy&&) = default;
        void set_attr(int v);
        int get_attr() const;
    private:
        int attr = 0;
};

, а реализация класса dummy.cpp просто

#include "dummy.hpp"
void dummy::set_attr(int v) { attr = v; }
int dummy::get_attr() const { return attr; }

файл интерфейса dummy_wrap.i:

%module dummy_wrap
%{
#include "dummy.hpp"
%}
%include "dummy.hpp"

и Makefile Я использую для компиляции и компоновки все

all: libdummy_lib.so _dummy_wrap.so
_dummy_wrap.so: dummy_wrap.o
    g++ -fPIC -shared -o _dummy_wrap.so dummy_wrap.o -L . -ldummy_lib -lpython3.8
dummy_wrap.o: dummy_wrap.cxx
    g++ -std=c++17 -fPIC -c dummy_wrap.cxx -I /usr/include/python3.8
dummy_wrap.cxx: dummy_wrap.i
    swig -Wall -c++ -python -py3 -o dummy_wrap.cxx dummy_wrap.i
libdummy_lib.so: dummy.o
    g++ -fPIC -shared -o libdummy_lib.so dummy.o
dummy.o: dummy.cpp dummy.hpp
    g++ -std=c++17 -fPIC -c dummy.cpp
clean:
    rm -f libdummy_lib.so dummy.o
    rm -f _dummy_wrap.so dummy_wrap.o dummy_wrap.cxx dummy_wrap.py

В linux, не забудьте обновить LD_LIBRARY_PATH, используя:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.

1 Ответ

0 голосов
/ 06 августа 2020

Итак, благодаря нескольким комментариям в исходной публикации, возможное решение - добавить метод clone(). Это можно было сделать, просто расширив заголовок C ++. Но поскольку некоторым это может показаться странным, поскольку во многих случаях метод clone() в C ++ вообще не нужен, мы можем расширить класс python с помощью SWIG. Просто возьмите dummy_wrap.i в примере и добавьте в конец файла следующий фрагмент кода

%extend dummy {
    dummy clone() const {
        return *$self;
    }
}

К сожалению, на этом это не заканчивается, так как наш код python должен быть изменен :

import dummy_wrap
d1 = dummy_wrap.dummy()
d2 = d1.clone()
d1.set_attr(12)
print(d2.get_attr()) # now this prints '0'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...