P
Phil Tomson
I'm finding that accessor methods on a wrapped C++ class end up creating
extra objects on the Ruby side. Here's an example to illustrate:
The following Ruby code uses two wrapped C++ classes (Point and Edge) in
the shared library TSP.so. An
Edge has two Point objects and the 'start_node' and 'end_node' methods on
Edge return Point objects.
#test_point.rb
require 'TSP'
include TSP
def count_points
np = 0
ObjectSpace.each_object(Point){|p|
np+=1
}
np
end
pa = Point.new(2,3)
pb = Point.new(10,6)
puts "number of points should be 2: count_points=#{count_points}"
edge = Edge.new(pa,pb,(pa-pb))
puts "number of points should be 2: count_points=#{count_points}"
puts edge.start_node #<-here's where the trouble starts
puts edge.end_node
puts "number of points should be 2: count_points=#{count_points}"
#end test_point.rb
Running test_point.rb prints:
making a new Point at 2,3
making a new Point at 10,6
number of points should be 2: count_points=2
number of points should be 2: count_points=2
(2,3)
(10,6)
number of points should be 2: count_points=4
So after calling the accessor methods 'start_node' and 'end_node' the
number of Point objects is 4 instead of 2. I think this is being caused
by SWIG_NewPointerObj. Maybe there's no way around it. I would have
expected that I would get a reference to an already existing Point object
instead of a new Point object being created.
Is there any way to do this so that no new Point objects are created when
calling Edge#end_node, Edge#start_node? Since my script calls these
methods a lot, lots of extra Point objects get created.
Here are the point.h/cpp and edge.h/cpp files:
#include <iostream>
class Point
{
// attr_accessor :x, :y
private:
int x_;
int y_;
//Point(Point& x){};
public:
Point(int x,int y):x_(x),y_(y){std::cout << "making a new Point at "
<< x <<","<<y<< std::endl;}
Point(Point& p){std::cout << "copy constructor" << std::endl;}
//calculate the distance between this point and other point
float operator -(Point& o);
bool operator ==(Point& o);
//accessors:
int x(){ return x_; }
int y(){ return y_; }
};
float Point:perator -(Point& o){
return sqrt((x_ - o.x())*(x_ - o.x())+(y_-o.y())*(y_ - o.y()));
};
bool Point:perator ==(Point& o){
return ((x_==o.x())&&(y_==o.y()));
};
#include "point.h"
class Edge
{
private:
Point* start_node_;
Point* end_node_;
float length_;
float tao_;
float quality_factor_;
public:
//constructor:
Edge(Point* s_node, Point* e_node, float len, float tao=TAO0);
//accessors
float length() const{return length_;}
Point* start_node() const {return start_node_;}
Point* end_node() const {return end_node_;}
float quality_factor() const { return quality_factor_;}
float tao() const {return tao_;}
void set_tao(float new_tao){ tao_ = new_tao; }
void calc_quality_factor();
};
#include "edge.h"
#include <math.h>
Edge::Edge(Point* s_node, Point* e_node, float len, float
tao):start_node_(s_node),end_node_(e_node),length_(len),tao_(tao){
this->calc_quality_factor();
}
void Edge::calc_quality_factor(){
quality_factor_=(tao_ * (pow((1.0/length_),BETA)) );
}
///end C++ code
Here is the TSP.i file:
%module TSP
%{
#include "constants.h"
#include "point.h"
#include "edge.h"
%}
%alias Edge::set_tao "tao=";
%include "constants.h"
%include "point.h"
%include "edge.h"
extra objects on the Ruby side. Here's an example to illustrate:
The following Ruby code uses two wrapped C++ classes (Point and Edge) in
the shared library TSP.so. An
Edge has two Point objects and the 'start_node' and 'end_node' methods on
Edge return Point objects.
#test_point.rb
require 'TSP'
include TSP
def count_points
np = 0
ObjectSpace.each_object(Point){|p|
np+=1
}
np
end
pa = Point.new(2,3)
pb = Point.new(10,6)
puts "number of points should be 2: count_points=#{count_points}"
edge = Edge.new(pa,pb,(pa-pb))
puts "number of points should be 2: count_points=#{count_points}"
puts edge.start_node #<-here's where the trouble starts
puts edge.end_node
puts "number of points should be 2: count_points=#{count_points}"
#end test_point.rb
Running test_point.rb prints:
making a new Point at 2,3
making a new Point at 10,6
number of points should be 2: count_points=2
number of points should be 2: count_points=2
(2,3)
(10,6)
number of points should be 2: count_points=4
So after calling the accessor methods 'start_node' and 'end_node' the
number of Point objects is 4 instead of 2. I think this is being caused
by SWIG_NewPointerObj. Maybe there's no way around it. I would have
expected that I would get a reference to an already existing Point object
instead of a new Point object being created.
Is there any way to do this so that no new Point objects are created when
calling Edge#end_node, Edge#start_node? Since my script calls these
methods a lot, lots of extra Point objects get created.
Here are the point.h/cpp and edge.h/cpp files:
#include <iostream>
class Point
{
// attr_accessor :x, :y
private:
int x_;
int y_;
//Point(Point& x){};
public:
Point(int x,int y):x_(x),y_(y){std::cout << "making a new Point at "
<< x <<","<<y<< std::endl;}
Point(Point& p){std::cout << "copy constructor" << std::endl;}
//calculate the distance between this point and other point
float operator -(Point& o);
bool operator ==(Point& o);
//accessors:
int x(){ return x_; }
int y(){ return y_; }
};
float Point:perator -(Point& o){
return sqrt((x_ - o.x())*(x_ - o.x())+(y_-o.y())*(y_ - o.y()));
};
bool Point:perator ==(Point& o){
return ((x_==o.x())&&(y_==o.y()));
};
#include "point.h"
class Edge
{
private:
Point* start_node_;
Point* end_node_;
float length_;
float tao_;
float quality_factor_;
public:
//constructor:
Edge(Point* s_node, Point* e_node, float len, float tao=TAO0);
//accessors
float length() const{return length_;}
Point* start_node() const {return start_node_;}
Point* end_node() const {return end_node_;}
float quality_factor() const { return quality_factor_;}
float tao() const {return tao_;}
void set_tao(float new_tao){ tao_ = new_tao; }
void calc_quality_factor();
};
#include "edge.h"
#include <math.h>
Edge::Edge(Point* s_node, Point* e_node, float len, float
tao):start_node_(s_node),end_node_(e_node),length_(len),tao_(tao){
this->calc_quality_factor();
}
void Edge::calc_quality_factor(){
quality_factor_=(tao_ * (pow((1.0/length_),BETA)) );
}
///end C++ code
Here is the TSP.i file:
%module TSP
%{
#include "constants.h"
#include "point.h"
#include "edge.h"
%}
%alias Edge::set_tao "tao=";
%include "constants.h"
%include "point.h"
%include "edge.h"