C++类在Python中使用SWIG的奇怪行为
Strange behaviour of C++ class in Python with SWIG
我在C++中有一个类,有两种方法(一个大项目的一部分(。这些方法执行非常相似的工作:第一个方法规范化一个向量并返回它,而第二个返回一个规范化的向量而不改变原始向量。
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;
};
我用SWIG(通过cmake(为这个类构建了Python绑定。
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})
C++的行为很好。
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;
}
输出:
(1, 1, 0)
(0.707107, 0.707107, 0)
(0.707107, 0.707107, 0)
但是,它在Python中的行为非常奇怪:
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() )
输出:
(1, 1, 0)
(0.707107, 0.707107, 0)
(0, 0.707107, 0)
第二种方法(normalized()
(按预期工作,但第一种方法(normalize()
(则不然。是什么原因造成的?关于如何解决此问题的任何建议?
@donkopotamus和@JensMunk是对的。
您的代码在 Python 中不正确,因为临时变量的生存期不同。
C++临时变量 (v1+v2( 的生存期是 C++ 中函数调用的整个序列。对于每个函数调用,通过SWIG包装器进行的Python调用,即通过不同的Python对象。对于 Python:
(v1+v2( - 构造一个临时 Python 对象 (tp1 = v1 + v2(,其生存期与调用序列不同。
(v1+v2(.normalized(( - 产生另一个临时 Python 对象 (tp2_1(;(
v1+v2(.normalize((- 生成另一个临时 Python 对象 (tp2_2(,该对象在内部引用第一个临时 Python 对象 (tp1(。
临时 Python 对象 (tp1 = v1 + v2( 递减引用计数器,现在可以进行垃圾回收,从而使 tp2_2 的内容无效。
(v1+v2(.normalized((.toString(( - 生成一个由有效tp2_1组成的临时 Python 对象 (tp3_1(,现在可以对其进行垃圾回收tp2_1;
(v1+v2(.normalize((.toString(( - 从可能损坏的tp2_2
中生成一个临时 Python 对象 (tp3_2(。
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 如果C++对象的类在另一个boost模块中声明,如何使用boost将指向该对象的指针返回到python
- 使用 thread 类在 C++ 中构造线程的动态数组时出错
- SWIG Java 在使用 -DSWIGWORDSIZE64 时将int64_t转换为 jlong
- 介绍类 在C++中查找圆半径的问题
- 有没有办法让类在C++中转换自己
- 使用类在C++中存储和列出变量/方法是否是一种好的做法
- 使类在使用时调用正确的构造函数
- C++:使用类在向量中搜索特定元素时,我得到了错误的结果
- 结构和类在C++中真的等价吗?
- 这个工厂类在这个C++视频中的意义何在?
- 是否允许类在程序中的不同翻译单元之间具有不同的定义?
- OpenCL 错误类在主机C++给出错误
- 如果类在堆上,函数是转到堆还是堆栈?
- 错误:基类在从基类父派生类 Son 时未定义
- 虚拟基类在内部如何工作?编译器如何解析对基方法的调用?
- 如何使 SWIG 绑定类在 Lua 中使用运算符?
- C++类在Python中使用SWIG的奇怪行为
- SWIG - 如何忽略C++不需要公开的类(在 Java 中)?