# Pointers

## The Problem With Pointers

In general, raw pointers passed to or returned from functions are problematic for Boost.Python because pointers have too many potential meanings. Is it an iterator? A pointer to a single element? An array? When used as a return value, is the caller expected to manage (delete) the pointed-to object or is the pointer really just a reference? If the latter, what happens to Python references to the referent when some C++ code deletes it?

There are a few cases in which pointers are converted automatically:

- Both const- and non-const pointers to wrapped class instances can be passed to C++ functions.
- Values of type `const char*` are interpreted as null-terminated 'C' strings and when passed to or returned from C++ functions are converted from/to Python strings.

### Can you avoid the problem?

My first piece of advice to anyone with a case not covered above is ``find a way to avoid the problem.'' For example, if you have just one or two functions that return a pointer to an individual `const T`, and `T` is a wrapped class, you may be able to write a ``thin converting wrapper'' over those two functions as follows:

>     const Foo* f(); // original function
>     const Foo& f_wrapper() { return *f(); }
>       ...
>     my_module.def(f_wrapper, "f");

Foo must have a public copy constructor for this technique to work, since Boost.Python converts `const T&` values `to_python` by copying the `T` value into a new extension instance.

## Dealing with the problem

The first step in handling the remaining cases is to figure out what the pointer means. Several potential solutions are provided in the examples that follow:

### Returning a pointer to a wrapped type

#### Returning a const pointer

If you have lots of functions returning a `const T*` for some wrapped `T`, you may want to provide an automatic `to_python` conversion function so you don't have to write lots of thin wrappers. You can do this simply as follows:

>     BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
>       PyObject* to_python(const Foo* p) {
>          return to_python(*p); // convert const Foo* in terms of const Foo&
>       }
>     BOOST_PYTHON_END_CONVERSION_NAMESPACE

#### If you can't (afford to) copy the referent, or the pointer is non-const

If the wrapped type doesn't have a public copy constructor, if copying is extremely costly (remember, we're dealing with Python here), or if the pointer is non-const and you really need to be able to modify the referent from Python, you can use the following dangerous trick. Why dangerous? Because python can not control the lifetime of the referent, so it may be destroyed by your C++ code before the last Python reference to it disappears:

>     BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
>       PyObject* to_python(Foo* p)
>       {
>           return boost::python::python_extension_class_converters<Foo>::ptr_to_python(p);
>       }

>       PyObject* to_python(const Foo* p)
>       {
>           return to_python(const_cast<Foo*>(p));
>       }
>     BOOST_PYTHON_END_CONVERSION_NAMESPACE

This will cause the Foo* to be treated as though it were an owning smart pointer, even though it's not. Be sure you don't use the reference for anything from Python once the pointer becomes invalid, though. Don't worry too much about the `const_cast<>` above: Const-correctness is completely lost to Python anyway!

### [In/]Out Parameters and Immutable Types

If you have an interface that uses non-const pointers (or references) as in/out parameters to types which in Python are immutable (e.g. int, string), there simply is no way to get the same interface in Python. You must resort to transforming your interface with simple thin wrappers as shown below:

>     const void f(int* in_out_x); // original function
>     const int f_wrapper(int in_x) { f(in_x); return in_x; }
>       ...
>     my_module.def(f_wrapper, "f");

Of course, [in/]out parameters commonly occur only when there is already a return value. You can handle this case by returning a Python tuple:

>     typedef unsigned ErrorCode;
>     const char* f(int* in_out_x); // original function
>      ...
>     #include <boost/python/objects.hpp>
>     const boost::python::tuple f_wrapper(int in_x) {
>       const char* s = f(in_x);
>       return boost::python::tuple(s, in_x);
>     }
>       ...
>     my_module.def(f_wrapper, "f");

Now, in Python:

>     >>> str,out_x = f(3)

Previous: Enums Up: Top

© Copyright David Abrahams 2000. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.

Updated: Nov 26, 2000