Comportement étrange de la classe C ++ en Python avec SWIG

Oleg Titov

J'ai une classe en C ++ avec deux méthodes (une partie d'un grand projet). Les méthodes font un travail très similaire: la première normalise un vecteur et le renvoie, tandis que la seconde renvoie un vecteur normalisé sans altérer l'original.

vector3.h :

class Vector3
{
public:
  Vector3(double a = 0.0, double b = 0.0, double c = 0.0) 
      : x(a), y(b), z(c) {}
  Vector3(const Vector3& other) : x(other.x), y(other.y), z(other.z) {}
  double length() const { return sqrt(x*x+y*y+z*z); }
  Vector3& normalize()
  {
    float_type n = length();
    n = float_type(1.0) / ( n ? n : 1.0 );
    this->x *= n;
    this->y *= n;
    this->z *= n;
    return *this;
  }
  Vector3 normalized() const
  {
    Vector3 v(*this);
    v.normalize();
    return v;
  }
  std::string toString()
  {
    std::ostringstream strm;
    strm << '(' << x << ", " << y << ", " << z << ')' ;
    return strm.str();
  }
  Vector3 operator+(const Vector3& other) const
  {
    return Vector3(x + other.x, y + other.y, z + other.z);
  }

private:
  double x,y,z;
};

Je construis des liaisons Python pour cette classe avec SWIG (via cmake).

vector3.i :

%include <stl.i>
%include <carrays.i>
%include <cpointer.i>
%module vectortest
%{
#include "vector3.h"
%}
%include "vector3.h"

CMakeLists.txt :

cmake_minimum_required(VERSION 2.8)

add_executable("vtest" "vtest.cpp")

find_package(SWIG)
include(${SWIG_USE_FILE})

find_package(PythonLibs)
find_package(PythonInterp)

include_directories(${CMAKE_SOURCE_DIR})
include_directories(${PYTHON_INCLUDE_DIRS})

SET(CMAKE_SWIG_FLAGS "")
SET_SOURCE_FILES_PROPERTIES(SOURCE vector3.i PROPERTIES CPLUSPLUS ON)
SWIG_ADD_MODULE(vectortest_python python vector3.i )
SWIG_LINK_LIBRARIES(vectortest_python ${PYTHON_LIBRARIES} ${LIBS})
set_target_properties(_vectortest_python PROPERTIES PREFIX "_" OUTPUT_NAME "vectortest")

execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print (get_python_lib())" OUTPUT_VARIABLE PYTHON_SITE_PACKAGES OUTPUT_STRIP_TRAILING_WHITESPACE)

install(TARGETS ${SWIG_MODULE_vectortest_python_REAL_NAME} DESTINATION ${PYTHON_SITE_PACKAGES})
install(FILES ${CMAKE_BINARY_DIR}/vectortest.py DESTINATION ${PYTHON_SITE_PACKAGES})

Le comportement en C ++ est correct.

vtest.cpp :

#include <iostream>
#include "vector3.h"

int main()
{
  Vector3 v1(1,0,0);
  Vector3 v2(0,1,0);

  std::cout << (v1+v2).toString() << std::endl;
  std::cout << (v1+v2).normalized().toString() << std::endl;
  std::cout << (v1+v2).normalize().toString() << std::endl;

  return 0;
}

Le résultat:

(1, 1, 0)
(0.707107, 0.707107, 0)
(0.707107, 0.707107, 0)

Cependant, son comportement en Python est assez étrange:

vtest.py :

#!/usr/bin/python3

from vectortest import Vector3

v1 = Vector3(1,0,0)
v2 = Vector3(0,1,0)
print( (v1+v2).toString() )
print( (v1+v2).normalized().toString() )
print( (v1+v2).normalize().toString() )

les sorties:

(1, 1, 0)
(0.707107, 0.707107, 0)
(0, 0.707107, 0)

La deuxième méthode ( normalized()) fonctionne comme prévu, mais pas la première ( normalize()). Qu'est-ce qui cause cela? Des suggestions sur la façon de résoudre ce problème?

Luart

@donkopotamus et @JensMunk ont ​​raison.
Votre code est incorrect en Python car la durée de vie des variables temporaires diffère.
La durée de vie de la variable temporaire C ++ (v1 + v2) est la séquence entière des appels de fonction en C ++. Appels Python effectués sur les wrappers SWIG pour chaque appel de fonction, c'est-à-dire sur les objets Python distincts . Pour Python:

(v1 + v2) - un objet Python temporaire (tp1 = v1 + v2) est construit, dont la durée de vie diffère de la séquence d'appels.

(v1 + v2) .normalized () - renvoie un autre objet Python temporaire (tp2_1);
(v1 + v2) .normalize () - renvoie un autre objet Python temporaire (tp2_2) qui fait référence en interne au premier objet Python temporaire (tp1).
L'objet Python temporaire (tp1 = v1 + v2) décrémente le compteur de référence et peut être récupéré maintenant, invalidant le contenu de tp2_2.

(v1 + v2) .normalized (). toString () - renvoie un objet Python temporaire (tp3_1) créé à partir du tp2_1 valide, tp2_1 peut être récupéré maintenant;
(v1 + v2) .normalize (). toString () - renvoie un objet Python temporaire (tp3_2) à partir du tp2_2 éventuellement corrompu
...

Cet article est collecté sur Internet, veuillez indiquer la source lors de la réimpression.

En cas d'infraction, veuillez [email protected] Supprimer.

modifier le
0

laisse moi dire quelques mots

0commentaires
connexionAprès avoir participé à la revue

Articles connexes

La comparaison de la classe wrapper avec la primitive en utilisant equals () donne un comportement étrange

Comportement étrange de StampedLock avec la classe Thread

Envelopper la classe C++ en Python avec SWIG

Comportement étrange avec la classe active PHP

Comportement étrange d'un destructeur de classe en C ++

Comportement étrange en utilisant FLASK socketIO en python avec l'éventlet de la bibliothèque

comportement étrange lors de l'utilisation de la liste d'autres objets de classe comme attribut de classe en python

Comportement étrange en python avec dict de fonctions lambda

Comportement étrange avec les tableaux de chaînes en C

Comportement étrange de l'opérateur `not` avec la liste python

Comportement étrange de la boucle C for avec i ++ comme condition

La suppression de fichiers en python donne un comportement étrange

Le comportement étrange de la fonction d'impression en python

En python3: comportement étrange de la liste (itérables)

comportement étrange de la constante 'e' en Python

Comportement étrange de la fonction m.erase () en C ++?

Comportement étrange avec découpage en python

Comportement étrange de Python avec énumérer

Comportement étrange avec beaucoup de nombres python

Comportement étrange avec l'opérateur défini comme ami à l'intérieur de la classe

Travailler avec des chaînes en C, strcat et le comportement étrange de la terminaison null ! (#débutant)

Comportement étrange de division en python

Comportement de thread étrange en python

Comportement de portée étrange en python

Comportement étrange en essayant de trouver l'attribut src de la classe img

Sortie étrange avec la fonction de lecture de classe C ++

Comportement étrange de la socket Python

Comportement étrange lors de la création d'attributs python dans la classe cdef cython

Comportement étrange de la classe récursive dans la boucle for

TOP liste

  1. 1

    J'ai besoin de savoir si ces deux phrases sont les mêmes en programmation

  2. 2

    Javascript indiquant "impossible de définir la propriété 'innerHTML' sur null"

  3. 3

    Nextcloud avec Docker: impossible de créer ou d'écrire dans le répertoire de données

  4. 4

    La taille de la forme n'est pas égale à la taille de la cellule du tableau et ajuste le texte à l'intérieur de la forme

  5. 5

    Trouver l'intersection et l'union de deux rectangles

  6. 6

    Comment changer la couleur de la police dans R?

  7. 7

    Empêcher l'allocation de mémoire dans la génération de combinaison récursive

  8. 8

    Référencement des assemblys de structure .net 4.7 dans la solution .net core 2

  9. 9

    Compter combien de fois un nombre apparaît dans un tableau aléatoire

  10. 10

    Pourquoi utiliser Asyncio ne réduit pas le temps d'exécution global en Python et n'exécute pas les fonctions simultanément?

  11. 11

    Comment convertir une chaîne en tuple en utilisant `reads`?

  12. 12

    java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver

  13. 13

    comment afficher un bouton au-dessus d'un autre élément ?

  14. 14

    Création d'un nouvel objet d'une classe avec un nouveau nom en cliquant sur un bouton dans java swing

  15. 15

    comment supprimer "compte de connexion google" à des fins de développement - actions sur google

  16. 16

    Restauration de la sauvegarde de la base de données SQL Server sur la version inférieure

  17. 17

    Créer un graphique à barres avec une fréquence relative / à partir d'un objet de table dans R

  18. 18

    Création d'un rappel python pour une fonction C à partir d'une DLL avec un tampon char.

  19. 19

    java.lang.NoClassDefFoundError: org / springframework / data / repository / config / BootstrapMode

  20. 20

    comment le contrôle de tableau javascript devrait-il être

  21. 21

    impossible d'ouvrir un nouvel onglet dans react, ajoute localhost: 3000 sur le lien?

chaudétiquette

Archive