Teuchos - Trilinos Tools Package Version of the Day
Public Member Functions | Protected Attributes | Related Functions
Teuchos::OpaqueWrapper< Opaque > Class Template Reference

Base class for wrapped opaque objects. More...

#include <Teuchos_OpaqueWrapper.hpp>

Inheritance diagram for Teuchos::OpaqueWrapper< Opaque >:
Teuchos::OpaqueWrapperWithFree< Opaque, OpaqueFree >

List of all members.

Public Member Functions

 OpaqueWrapper (Opaque opaque)
 Constructor that accepts and wraps a raw handle.
 operator Opaque () const
 Implicit type conversion from wrapper to raw handle.
Opaque operator() () const
 Explicit type conversion from wrapper to raw handle.

Protected Attributes

Opaque opaque_
 The actual handle.

Related Functions

(Note that these are not member functions.)

template<class Opaque >
RCP< OpaqueWrapper< Opaque > > opaqueWrapper (Opaque opaque)
 Create a new OpaqueWrapper object without a free function.
template<class Opaque , class OpaqueFree >
RCP< OpaqueWrapper< Opaque > > opaqueWrapper (Opaque opaque, OpaqueFree opaqueFree)
 Create a new OpaqueWrapper object with a free function.

Detailed Description

template<class Opaque>
class Teuchos::OpaqueWrapper< Opaque >

Base class for wrapped opaque objects.

Template Parameters:
OpaqueType of the opaque object (a.k.a. handle).

If you want to create an RCP to an opaque object, use the opaqueWrapper() nonmember template function. The type of an RCP to an opaque object T is RCP<OpaqueWrapper<T> >.

In order to understand this documentation, you must first have learned how to use RCP (Teuchos' reference-counted pointer class) to manage dynamically allocated memory and other resources. It also helps to be familiar with MPI (the Message Passing Interface for distributed-memory parallel programming), but this is not required.

Many different software libraries use the opaque object or opaque handle idiom to hide the internals of a data structure from users. This standard technique allows users to treat an instance of a data structure as a handle. Users may pass the handle around as if it were a simple value type (like int), and must call nonmember functions in order to create, operate on, use, or destroy instances of the data structure. The MPI (Message Passing Interface) standard is full of examples of the opaque object idiom, including MPI_Comm (for communicators), MPI_Datatype (for standard and custom data types), and MPI_Op (for standard and custom reduction operations).

Opaque handles are a useful technique, but they interfere with correct use of RCP, as we will explain below. This base class allows opaque objects to be wrapped by a real object, whose address you can take. This is needed in order to wrap an opaque object in a RCP, for example.

This class was motivated in particular by MPI's common use of the opaque object idiom. For MPI, passing MPI_Comm, MPI_Datatype, and MPI_Op objects around by handles hides implementation details from the user. Handles also make it easier to access MPI functionality from Fortran, so that C, C++, and Fortran can all share the same handle mechanism. In fact, some MPI implementations (such as MPICH, at least historically if not currently) simply implement these handles all as integers. (As the MPI standard's advice to implementers suggests, such an implementation would likely maintain a table for each MPI process that maps the integer value to a pointer to the corresponding object.) For example, MPI_Comm might be a typedef to int, and MPI_COMM_WORLD might be a literal integer value:

 typedef int MPI_Comm;
 #define MPI_COMM_WORLD 42

In this case, the expression rcp(&MPI_COMM_WORLD) would not even compile, since one cannot take the address of an integer literal. To make this this compile, one might try the following:

 // THIS FUNCTION IS WRONG.  IT MAY SEGFAULT.
 Teuchos::RCP<MPI_Comm> getMpiCommPtr()
 {
   MPI_Comm comm = MPI_COMM_WORLD;
   // WRONG!!!  comm is a stack variable!
   return Teuchos::rcp (&comm, false);
 }

Using the returned communicator would result in undefined behavior, which in practice might be a segfault, memory corruption, or MPI getting severely confused. This is because the stack variable comm, which may be just an integer, disappears at the end of the function. Its address would no longer point to valid memory after the function returns.

The following code is syntactically correct, but may leak memory:

 // THIS CODE LEAKS MEMORY FOR GENERAL MPI_Comm OBJECTS.
 Teuchos::RCP<MPI_Comm> getMpiCommPtr (MPI_Comm comm)
 {
   MPI_Comm *pComm = new MPI_Comm (comm);
   // Works for comm==MPI_COMM_WORLD or MPI_COMM_SELF;
   // leaks memory for user-created MPI_Comm objects.
   return Teuchos::rcp (pComm);
 }

The above implementation of getMpiCommPtr() is correct only for the standard MPI_Comm objects provided by MPI, like MPI_COMM_WORLD and MPI_COMM_SELF. It is not correct, and in fact may leak memory, for custom MPI_Comm objects that the user creates by calling functions like MPI_Comm_split(). This is because user-created MPI_Comm objects must be freed by MPI_Comm_free(). Other kinds of opaque objects, like MPI_Datatype and MPI_Op, have their own free functions. Thus, even if opaque handles have the type integer, they really behave like pointers or references. Some of them can and should be freed at the end of their useful lives; others must not. (Compare std::ostream; std::cout should never be closed by typical user code, but an output file should be closed.)

We work around this by providing the OpaqueWrapper template base class and the opaqueWrapper() nonmember template function. Use this function to wrap an opaque handle (like an MPI_Comm) in an RCP. This ensures that the RCP does the right thing in case the handle must be freed. For example, to wrap MPI_COMM_WORLD in a RCP, just do this:

 RCP<OpaqueWrapper<MPI_Comm> > comm = opaqueWrapper (MPI_COMM_WORLD);

If you instead want to create a custom MPI_Comm using a function like MPI_Comm_split(), then you may wrap it in an RCP as follows:

 MPI_Comm rawComm;
 // We omit all arguments but the last of MPI_Comm_split, for clarity.
 int errCode = MPI_Comm_split (..., &rawComm);
 if (errCode != MPI_SUCCESS) {
   // Handle the error
 }
 RCP<OpaqueWrapper<MPI_Comm> > comm = opaqueWrapper (rawComm, MPI_Comm_free);

The second argument to opaqueWrapper() is a "free" function. It takes a pointer to the opaque handle, and its return value (if any) is ignored. Users are responsible for knowing whether to provide a free function to opaqueWrapper(). In this case, because we created an MPI_Comm dynamically using a communicator "constructor" function, the MPI_Comm must be "freed" after use. RCP will automatically call the "free" function once the reference count of comm reaches zero.

Users are not allowed to construct an OpaqueWrapper object explicitly. You must use the opaqueWrapper() nonmember function to do so.

Definition at line 210 of file Teuchos_OpaqueWrapper.hpp.


Constructor & Destructor Documentation

template<class Opaque>
Teuchos::OpaqueWrapper< Opaque >::OpaqueWrapper ( Opaque  opaque) [inline]

Constructor that accepts and wraps a raw handle.

Users typically never have to invoke the constructor explicitly. The opaqueWrapper() nonmember template function does this for them.

Definition at line 216 of file Teuchos_OpaqueWrapper.hpp.


Member Function Documentation

template<class Opaque>
Teuchos::OpaqueWrapper< Opaque >::operator Opaque ( ) const [inline]

Implicit type conversion from wrapper to raw handle.

Users typically never have to convert directly from an OpaqueWrapper to the raw handle that it wraps. For example, if you have an RCP<OpaqueHandle<T> >, just deferencing the RCP will return the raw handle via this implicit type conversion operator:

 // We omit the right-hand side of this assignment, for simplicity.
 RCP<OpaqueWrapper<T> > wrapped = ...;
 // RCP's <tt>operator*</tt> returns OpaqueWrapper<T>&.
 // In turn, the operator below automatically converts to T.
 T raw = *wrapped;

Definition at line 233 of file Teuchos_OpaqueWrapper.hpp.

template<class Opaque>
Opaque Teuchos::OpaqueWrapper< Opaque >::operator() ( ) const [inline]

Explicit type conversion from wrapper to raw handle.

Users typically never have to convert directly from an OpaqueWrapper to the raw handle that it wraps. However, in case they do, we provide this operator.

Definition at line 240 of file Teuchos_OpaqueWrapper.hpp.


Friends And Related Function Documentation

template<class Opaque >
RCP< OpaqueWrapper< Opaque > > opaqueWrapper ( Opaque  opaque) [related]

Create a new OpaqueWrapper object without a free function.

See the documentation of OpaqueWrapper for a detailed explanation of why and how to use this function.

Definition at line 325 of file Teuchos_OpaqueWrapper.hpp.

template<class Opaque , class OpaqueFree >
RCP< OpaqueWrapper< Opaque > > opaqueWrapper ( Opaque  opaque,
OpaqueFree  opaqueFree 
) [related]

Create a new OpaqueWrapper object with a free function.

See the documentation of OpaqueWrapper for a detailed explanation of why and how to use this function.

Definition at line 341 of file Teuchos_OpaqueWrapper.hpp.


Member Data Documentation

template<class Opaque>
Opaque Teuchos::OpaqueWrapper< Opaque >::opaque_ [protected]

The actual handle.

This is protected and not private so that OpaqueWrapperWithFree can access it. In general, one should avoid using protected data, but it would be silly to add member functions just for this simple use case.

Definition at line 249 of file Teuchos_OpaqueWrapper.hpp.


The documentation for this class was generated from the following file:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines