Each builder gives to KeyValue a pointer to an object that is then,
stored in KeyValue's repository. Normally, the memory occupied by any of
these object is allocated on the heap (through operator new
)
and to prevent memory leaks, smart pointers must be used. The most popular
smart pointer types are, probably,
::boost::
and
shared_ptr
::boost::
and KeyValue
provides good support for some of them. Some projetcs, however, have a
genuine need for other types of smart pointers and KeyValue is flexible
with respect to this point.intrusive_ptr
Obviously, KeyValue needs to know about the smart pointer type used by the bridge and core libraries. The next sections explain how to provide the required information.
This file provides the information on the smart pointer used by
bridge and core libraries. The name of this file is flexible but, for
sake of concreteness, in this manual it will be called
PtrTraits.h
.
PtrTraits.h
must be included at the very
beginning of all builder and calculator source files. (For instance,
every processor implemented by the bridge-example library
#include
s the file
bridge-example/PtrTraits.h
.)
In the sequel, we shall see the four tasks that
PtrTraits.h
must acomplish. Section 14.1.5 presents examples of pointer
traits files that come with KeyValue and can be used by bridge
developers as samples for writing their onw.
value::PtrTraits
This struct depends on a parameter
ObjectType
and provides a
typedef
, namely Type_
, to the
smart pointer class that points to objects of type
ObjectType
.
For instance, in bridge-example/PtrTraits.h
we have:
namespacekeyvalue
{ namespacevalue
{ template <typename ObjectType> structPtrTraits
{ typedef::boost::shared_ptr
<ObjectType> Type_; }; } // namespacevalue
} // namespacekeyvalue
This
tells KeyValue that, as far as the bridge-example library is
concerned, a pointer to ObjectType
is a
::boost::shared_ptr
<ObjectType>
.
value::PtrTraits
for
voidThe general implementation of
defines the
smart pointer for each specific type of object. However, KeyValue's
repository is a container for uniform storage, that is, stored
pointers must have the same type. This situation is analogous to the
classic example of polymorphism found in many C++ text books where a
value::PtrTraits
stores pointers to several types of shapes like
::std::vector
<Shape*
>
,
Square
, etc.Circle
The specialization of
for
value::PtrTraits
void
tells KeyValue what is the type of
pointer that the repository stores.
For instance, in bridge-example/PtrTraits.h
we have:
namespacekeyvalue
{ namespacevalue
{ template <> structPtrTraits
<void> { typedef ::boost::shared_ptr<::core::Polygon
> Type_; }; } // namespacevalue
} // namespacekeyvalue
This
means that KeyValue uniformly stores
s.
Hence, when a
::boost::shared_ptr
<::core::Polygon
>
is given to KeyValue, it is cast to a
::boost::shared_ptr
<::core::Triangle
>
before being stored. Later, when the bridge-example library asks for
this object back, KeyValue does the oposite cast.::boost::shared_ptr
<::core::Polygon
>
As we have seen, KeyValue casts pointers to specific types to pointers to the generic type and vice versa. The cast specific-to-generic is performed by a constructor and this point is explained in more details in Section 14.3. The generic-to-specific cast is performed by a template function which, essentially, has the following signature:
template <typename ObjectType>value::PtrTraits
<ObjectType>::Type_dynamic_pointer_cast
(constvalue::PtrTraits
<void>::Type_&genericPointer
);
The implementation must obey the semantics of the C++ built-in
cast operator dynamic_cast
. Specifically, if
does point to an
genericPointer
ObjectType
, then
dynamic_pointer_cast
returns a
pointing to the same object. Otherwise, a NULL
value::PtrTraits
<ObjectType>::Type_
is returned.value::PtrTraits
<ObjectType>::Type_
This function is named after
::boost::
which
satisfies the requirement describe above. Hence, for some boost smart
pointers,
dynamic_pointer_cast
::boost::
is
exactly what is needed. More precisely,
dynamic_pointer_cast
PtrTraits.h
should not implement
when the bridge
library uses either
dynamic_pointer_cast
::boost::
or
shared_ptr
::boost::
. In this
case, KeyValue calls
intrusive_ptr
::boost::
.dynamic_pointer_cast
For example, bridge-example/PtrTraits.h
sets the specific pointer to be
and the generic pointer to be
::boost::shared_ptr
<ObjectType>
.
Hence, it does not implement
::boost::shared_ptr
<::core::Polygon
>
. Notice that,
in this case, the signature above readsdynamic_pointer_cast
template <typename ObjectType>::boost::shared_ptr
<ObjectType>dynamic_pointer_cast
(const::boost::shared_ptr
<::core::Polygon
>&genericPointer
);
and
matches the one in namespace ::boost
whose implementation
is #include
d into
bridge-example/PtrTraits.h
through
boost/shared_ptr.hpp
.
If you do need to implement
, then you can
place it in one of the following namespaces:dynamic_pointer_cast
The global namespace.
Do not do this! It does work but is considered bad practice (namespace pollution).
Namespace value
.
The call to
comes
from this namespace and then, if this function is there, then
the compiler will find it.dynamic_pointer_cast
The namespace that contains the smart pointer.
For instance, when using
::boost::
, the
function can be (and it is) in namespace shared_ptr
::boost
.
Analogously, if your curstom smart pointer belongs to namespace
::foo::bar
, then
can be
placed in dynamic_pointer_cast
::foo::bar
as well.
Briefly, this macro can be uniformly set in this way:
#ifndef KEYVALUE_PTR_TRAITS_FILE #define KEYVALUE_PTR_TRAITS_FILE __FILE__ #endif
Section 14.2 provides detailed information about this macro.
Given the popularity of boost libraries, KeyValue provides three examples of pointer traits files based on some boost smart pointers. Bridge developers can use any of them almost out of the box:
keyvalue/value/ptr-traits/shared_ptr.h
This implementation is based on
::boost::shared_ptr
and can be used
when all core library types managed by KeyValue derive from
the same base polymorphic class. The original file must be
adapted to reflect the correct base class.
Notice that
bridge-example/PtrTraits.h
is basically a
copy of this file with the base polymorphic class set to
.::boost::shared_ptr
<::core::Polygon
>
keyvalue/value/ptr-traits/intrusive_ptr.h
Similarly to the previous file but based on
::boost::intrusive_ptr
, you can use
this file when you have a common polymorphic base class for
all core library types managed by KeyValue. Here again, you
must edit the file to use the correct base class. Other
constraints on the base class, regarding the referencing
counting, are explained in boost's
documentation and are outside the scope of this manual.
keyvalue/value/ptr-traits/AnyPtr.h
This implemenation is based on util::AnyPtr
. Opposite to the
previous implementations, this one does not require a commom
polymorphic base class and this file can be used as it is with
no need for adaptations.
The implementation of util::AnyPtr
is very similar
to the one presented in [4].
None of the files above (or their derivatives) needs to provide
the implementation of
. Indeed, for
the first two the implementation is provided by boost and for the
third one the implementation is provided by KeyValue.dynamic_pointer_cast
The macro
must be set to the name of the pointer traits header file.
Unfortunately, there are two places where this macro is set and both
definitions must agree, otherwise weird errors can occur.KEYVALUE_PTR_TRAITS_FILE
config/config.mak
:You should set
to
either an absolute or a relative (with respect to
KEYVALUE_PTR_TRAITS_FILE
keyvalue
directory) path.
For instance, to use
bridge-example/bridge-example/PtrTraits.h
and assuming that KeyValue was unpacked in
/home/cassio/keyvalue-0.3
, you
set
KEYVALUE_PTR_TRAITS_FILE
:=/home/cassio/keyvalue-0.3/bridge-example/bridge-example/PtrTraits.h
Analogously,
if KeyValue was unpacked in
C:\Users\cassio\Documents\keyvalue-0.3
,
then use
KEYVALUE_PTR_TRAITS_FILE
:=C:/Users/cassio/Documents/keyvalue-0.3/bridge-example/bridge-example/PtrTraits.h
Alternatively, in both cases above, you can also use
KEYVALUE_PTR_TRAITS_FILE
:=../bridge-example/bridge-example/PtrTraits.h
This is the very same file that
points
to. Therefore, the simplest way of defining this macro is using
the standard predefined macro
KEYVALUE_PTR_TRAITS_FILE
:__FILE__
#ifndef KEYVALUE_PTR_TRAITS_FILE #define KEYVALUE_PTR_TRAITS_FILE __FILE__ #endif
KeyValue has some expectations on the smart pointers received from builders. This section covers the conditions that smart pointer implentations must verify.
Most smart pointers are implemented as template classes
parametrised on the type of object pointed to. Although this is
not a KeyValue's requirement, to
simplify the presentation, we will assume this is the case and we shall
call this template
.MinimalPointer
The interface that KeyValue requires
to implement is given
by the skeleton below.MinimalPointer
template <typename ObjectType> classMinimalPointer
{ public:MinimalPointer
(constMinimalPtr
&orig
);~MinimalPointer
(); };
As we can see,
must have a public copy-constructor and a public destructor (virtual or
not). We emphasize that this interface is the minimum requirement and smart pointers will
certainly extend it. Having said that, we notice the omission of
constructors (apart from the copy-constructor). Surely, there is no
class without a constructor but, because KeyValue does not create these
pointers (it only copies those created by the bridge), it does not
require any other particular constructor to be implemented.
Additionally, KeyValue does not dereference the pointer and, thus, does
not require the implementation of MinimalPointer
. The same holds for other methods usually
implemented by smart pointers.operator
->
()
Recall that KeyValue receives pointers to different types of
objects but, for uniform storage, casts them to a unique smart pointer
type. For the sake of this presentation, we will assume that this smart
pointer is a specialization of
when
MinimalPointer
ObjectType
is void
.
Its minimal interface is given below.
template <> classMinimalPointer
<void> { public:MinimalPointer
();~MinimalPointer
();MinimalPointer
&operator =
(constMinimalPointer
&orig
); booloperator ==
(constMinimalPointer
&rhs
) const; template <typename ObjectType>MinimalPointer
(constMinimalPtr
<ObjectType>&orig
); };
The following public methods must be implemented: the default
constructor, the destructor (virtual
or not), the
assignment operator, a comparison operator and a template constructor
taking a generic smart pointer as argument. The first three methods do
not need any further comments. Now, we shall consider how KeyValue uses
the last two.
Usually smart pointers implement
returning operator
bool
()false
, if the pointer is
NULL, or true
, if it is not. KeyValue
does not require that. Instead, it considers a pointer to be
NULL if, and only if, the result of comparing the
pointer (through
) with a
default-constructed one gives operator ==
()true
.
When KeyValue needs converting a
into a
MinimalPointer
<ObjectType>
it uses the template constructor above which can be
MinimalPointer
<void>explicit
or not.
[4] Neri, C., Twisting the RTTI System for
Safe Dynamic Casts of void*
in
C++, Dr.Dobbs, April 2011 (http://drdobbs.com/cpp/229401004).