Pointer values are wrapped in PyObjects, allowing pointers to be passed around from within Python.
Type checking is performed at run time. In the example below the int32* return value cannot be passed into a function taking a float64*.
With the following C++
// C++ code
namespace ns
{
$function+ int32* ReturnPtr()
{
static int32 x = 10;
return &x;
}
$function+ void PassPtr(int32* x)
{
std::cout << "PassPtr : *x = " << *x << '\n';
}
$function+ void PassFloat64Ptr(float64* x)
{
}
}
the following Python
# python code
# The pointer return value is wrapped in a PyObject.
p = ns.ReturnPtr()
# prints the value of the pointer. Eg '004262F4' on 32 bit platform
print 'p = ' + `p`
# Pointers of a compatible type can be passed into functions
ns.PassPtr( p )
# Causes TypeError at run time : Cannot assign float64* from int32*
ns.PassFloat64Ptr( p )
produces the following output
p = 0x00007FF757F58F64
PassPtr : *x = 10
Caught TypeError: Cannot assign float64* from int32*
Within Python a pointer to a signed integer can be reinterpreted as a pointer to an unsigned integer of the same size and vice versa.
With the following C++
// C++ code
namespace ns
{
$function+ int32* ReturnPtr()
{
static int32 x = -1;
return &x;
}
$function+ void PassPtr(uint32* x)
{
std::cout << "PassPtr : *x = " << *x << '\n';
}
}
the following Python
# python code
ns.PassPtr( ns.ReturnPtr() )
produces the following output
PassPtr : *x = 4294967295
Null Pointers are always represented using Py_None.
Note therefore that null pointers carry no type information. In the example below, Python happily allow the null int8* to be passed into a function taking a float64*
With the following C++
// C++ code
namespace ns
{
$function+ int8* ReturnNull()
{
return NULL;
}
$function+ void PassPtr(float64* p)
{
std::cout << "PassPtr : p = " << (void*) p << '\n';
}
}
the following Python
# python code
p = ns.ReturnNull()
if p:
print 'p is not null'
else:
print 'p is null'
ns.PassPtr( p )
ns.PassPtr( None )
produces the following output
p is null
PassPtr : p = 0000000000000000
PassPtr : p = 0000000000000000
A reflected class may be returned by value or pointer without having any impact on the syntax used for accessing reflected member variables or methods or accessing implemented interfaces.
With the following C++
// C++ code
namespace ns
{
$struct+ X
{
X(int32 v=0) : val(v) {}
$int32 val;
};
$function+ X ReturnX()
{
return X(100);
}
$function+ X* ReturnXPtr()
{
static X x(200);
return &x;
}
$function+ void IncVal(X* px)
{
++px->val;
}
}
the following Python
# python code
x1 = ns.ReturnX()
print 'x1.val = ' + `x1.val`
x1.val = x1.val + 10
ns.IncVal(x1)
print 'x1.val = ' + `x1.val`
x2 = ns.ReturnX()
print 'x2.val = ' + `x2.val`
x2.val = x2.val + 10
ns.IncVal(x2)
print 'x2.val = ' + `x2.val`
produces the following output
x1.val = 100
x1.val = 111
x2.val = 200
x2.val = 211
Generally speaking references are treated like pointers. The main difference is that Py_None cannot be passed to a function taking a reference. This error is trapped at run time.
With the following C++
// C++ code
namespace ns
{
$function+ int32& ReturnRef()
{
static int32 x = 10;
return x;
}
$function+ void Inc(int32& x)
{
++x;
}
}
the following Python
# python code
ns.Inc(ns.ReturnRef())
# TypeError : Can't initialise reference int32& from None
# ns.Inc(None)
Indirections are implicitly performed on pointers in order to coerce into references or values
With the following C++
// C++ code
namespace ns
{
$function+ void PassVal(int32 v)
{
std::cout << "Pass Val : " << v << '\n';
}
$function+ void PassPtr(int32* v)
{
std::cout << "Pass Ptr : " << *v << '\n';
}
$function+ void PassRef(int32& v)
{
std::cout << "Pass Ref : " << v << '\n';
}
$function+ void PassConstVal(const int32 v)
{
std::cout << "Pass ConstVal : " << v << '\n';
}
$function+ void PassConstPtr(const int32* v)
{
std::cout << "Pass ConstPtr : " << *v << '\n';
}
$function+ void PassConstRef(const int32& v)
{
std::cout << "Pass ConstRef : " << v << '\n';
}
$function+ int32 ReturnVal()
{
std::cout << "Return Val ";
return 1;
}
$function+ int32* ReturnPtr()
{
std::cout << "Return Ptr ";
static int32 s = 2;
return &s;
}
$function+ int32& ReturnRef()
{
std::cout << "Return Ref ";
static int32 s = 3;
return s;
}
$function+ const int32 ReturnConstVal()
{
std::cout << "Return Const Val";
return 4;
}
$function+ const int32* ReturnConstPtr()
{
std::cout << "Return Const Ptr";
static int32 s = 5;
return &s;
}
$function+ const int32& ReturnConstRef()
{
std::cout << "Return Const Ref";
static int32 s = 6;
return s;
}
}
the following Python
# python code
ns.PassVal(ns.ReturnVal())
ns.PassVal(ns.ReturnPtr())
ns.PassVal(ns.ReturnRef())
ns.PassVal(ns.ReturnConstVal())
ns.PassVal(ns.ReturnConstPtr())
ns.PassVal(ns.ReturnConstRef())
ns.PassConstVal(ns.ReturnVal())
ns.PassConstVal(ns.ReturnPtr())
ns.PassConstVal(ns.ReturnRef())
ns.PassConstVal(ns.ReturnConstVal())
ns.PassConstVal(ns.ReturnConstPtr())
ns.PassConstVal(ns.ReturnConstRef())
ns.PassConstPtr(ns.ReturnVal())
ns.PassConstPtr(ns.ReturnPtr())
ns.PassConstPtr(ns.ReturnRef())
ns.PassConstPtr(ns.ReturnConstVal())
ns.PassConstPtr(ns.ReturnConstPtr())
ns.PassConstPtr(ns.ReturnConstRef())
ns.PassConstRef(ns.ReturnVal())
ns.PassConstRef(ns.ReturnPtr())
ns.PassConstRef(ns.ReturnRef())
ns.PassConstRef(ns.ReturnConstVal())
ns.PassConstRef(ns.ReturnConstPtr())
ns.PassConstRef(ns.ReturnConstRef())
ns.PassPtr(ns.ReturnPtr())
ns.PassPtr(ns.ReturnRef())
ns.PassRef(ns.ReturnPtr())
ns.PassRef(ns.ReturnRef())
# Error. Const cast
#ns.PassPtr(ns.ReturnConstPtr())
#ns.PassRef(ns.ReturnConstPtr())
#ns.PassPtr(ns.ReturnConstRef())
#ns.PassRef(ns.ReturnConstRef())
# Error. Cannot convert from value to mutable pointer
#ns.PassPtr(ns.ReturnVal())
#ns.PassPtr(ns.ReturnConstVal())
#ns.PassRef(ns.ReturnVal())
#ns.PassRef(ns.ReturnConstVal())
produces the following output
Return Val Pass Val : 1
Return Ptr Pass Val : 2
Return Ref Pass Val : 3
Return Const Val Pass Val : 4
Return Const Ptr Pass Val : 5
Return Const Ref Pass Val : 6
Return Val Pass ConstVal : 1
Return Ptr Pass ConstVal : 2
Return Ref Pass ConstVal : 3
Return Const Val Pass ConstVal : 4
Return Const Ptr Pass ConstVal : 5
Return Const Ref Pass ConstVal : 6
Return Val Pass ConstPtr : 1
Return Ptr Pass ConstPtr : 2
Return Ref Pass ConstPtr : 3
Return Const Val Pass ConstPtr : 4
Return Const Ptr Pass ConstPtr : 5
Return Const Ref Pass ConstPtr : 6
Return Val Pass ConstRef : 1
Return Ptr Pass ConstRef : 2
Return Ref Pass ConstRef : 3
Return Const Val Pass ConstRef : 4
Return Const Ptr Pass ConstRef : 5
Return Const Ref Pass ConstRef : 6
Return Ptr Pass Ptr : 2
Return Ref Pass Ptr : 3
Return Ptr Pass Ref : 2
Return Ref Pass Ref : 3