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?
@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.
laisse moi dire quelques mots