From 2528431334b0c8aa07c85ec798be5fc9eb5b2add Mon Sep 17 00:00:00 2001
From: Boris Kolpackov In this chapter we present a high-level overview of ODB.
We will start with the ODB architecture and then outline the
workflow of building an application that uses ODB. We will
- conclude the chapter by contrasting the drawbacks of
- the traditional way of saving C++ objects to relational
- databases with the benefits of using ODB for object
- persistence. The next chapter takes a more hands-on approach
- and shows the concrete steps necessary to implement object
- persistence in a simple "Hello World" application.
@@ -884,12 +885,13 @@ for consistency.
1.1 Architecture and Workflow
+ 1.2 Benefits 1.3 Supported C++ Standards
ODB provides support for ISO/IEC C++ 1998 (C++98), ISO/IEC TR 19768
+ C++ Library Extensions (C++ TR1), and ISO/IEC C++ 2011 (C++11).
+ While the majority of the examples in this manual use C++98,
+ support for the new functionality and library components introduced in
+ TR1 and C++11 are discussed throughout the document. The c++11
+ example in the odb-examples
package also shows ODB
+ support for various C++11 features.
std::auto_ptr
to manage the returned object, we
could have also used another smart pointer, for example
- shared_ptr
from TR1 or Boost. For more information
+ std::unique_ptr
from C++11 or shared_ptr
+ from TR1, C++11, or Boost. For more information
on the object lifetime management and the smart pointers that we
can use for that, see Section 3.2, "Object
and View Pointers".
@@ -2279,16 +2291,18 @@ class name
or object relationships. In particular, a dynamically allocated object
or view that is returned as a raw pointer from a database operation
can be assigned to a smart pointer of our choice, for example
- std::auto_ptr
or shared_ptr
from TR1 or
- Boost.
+ std::auto_ptr
, std::unique_ptr
from C++11, or
+ shared_ptr
from TR1, C++11, or Boost.
However, to avoid any possibility of a mistake, such as forgetting
to use a smart pointer for a returned object or view, as well as to
simplify the use of more advanced ODB functionality, such as sessions
and bidirectional object relationships, it is recommended that you use
smart pointers with the sharing semantics as object and view pointers.
- The shared_ptr
smart pointer from TR1 or Boost is a good
- default choice.
shared_ptr
smart pointer from TR1, C++11, or Boost
+ is a good default choice. However, if sharing is not required and
+ sessions are not used, then std::unique_ptr
or
+ std::auto_ptr
can be used just as well.
ODB provides two mechanisms for changing the object or view pointer
type. We can use the --default-pointer
option to specify
@@ -2320,7 +2334,8 @@ class person
(view)" for more information on this pragma.
Built-in support that is provided by the ODB runtime library allows us
- to use the TR1 shared_ptr
and std::auto_ptr
as
+ to use shared_ptr
(TR1 or C++11),
+ std::unique_ptr
(C++11), or std::auto_ptr
as
pointer types. Plus, ODB profile libraries, that are available for
commonly used frameworks and libraries (such as Boost and Qt),
provide support for smart pointers found in these frameworks and
@@ -4165,6 +4180,26 @@ namespace odb
}
+
In C++11 we can use the auto
-typed variabe instead
+ of spelling the iterator type explicitly, for example:
+ for (auto i (r.begin ()); i != r.end (); ++i) + { + ... + } ++ +
The C++11 range-based for
-loop can be used to further
+ simplify the iteration:
+ for (person& p: r) + { + ... + } ++
The result iterator is an input iterator which means that the only two position operations that it supports are to move to the next object and to determine whether the end of the result stream @@ -4295,10 +4330,14 @@ namespace odb
The ODB runtime library provides built-in persistence support for all the
- commonly used standard C++ containers, namely,
+ commonly used standard C++98 containers, namely,
std::vector
, std::list
, std::set
,
std::multiset
, std::map
, and
- std::multimap
. Plus, ODB profile libraries, that are
+ std::multimap
as well as C++11 std::array
,
+ std::forward_list
, std::unordered_set
,
+ std::unordered_multiset
, std::unordered_map
,
+ and std::unordered_multimap
.
+ Plus, ODB profile libraries, that are
available for commonly used frameworks and libraries (such as Boost and
Qt), provide persistence support for containers found in these frameworks
and libraries (Part III, "Profiles"). It is also easy
@@ -4385,7 +4424,8 @@ private:
In ODB an ordered container is any container that maintains (explicitly
or implicitly) an order of its elements in the form of an integer index.
Standard C++ containers that are ordered include std::vector
- and std::list
. While elements in std::set
+ and std::list
as well as C++11 std::array
and
+ std::forward_list
. While elements in std::set
are also kept in a specific order, this order is not based on an
integer index but rather on the relationship between elements. As
a result, std::set
is not considered an ordered
@@ -4479,7 +4519,9 @@ private:
or may not guarantee a particular order of the elements that
it stores. Standard C++ containers that are considered set
containers for the purpose of persistence include
- std::set
and std::multiset
.
std::set
and std::multiset
as well
+ as C++11 std::unordered_set
and
+ std::unordered_multiset
.
The database table for a set container consists of at least
two columns. The first column contains the object id of a
@@ -4539,7 +4581,9 @@ private:
may or may not guarantee a particular order of the elements that
it stores. Standard C++ containers that are considered map
containers for the purpose of persistence include
- std::map
and std::multimap
.
std::map
and std::multimap
as well
+ as C++11 std::unordered_map
and
+ std::unordered_multimap
.
The database table for a map container consists of at least three columns. The first column contains the object id of a @@ -4643,7 +4687,8 @@ private:
Relationships between persistent objects are expressed with pointers or
containers of pointers. The ODB runtime library provides built-in support
- for the TR1 shared_ptr
/weak_ptr
,
+ for shared_ptr
/weak_ptr
(TR1 or C++11),
+ std::unique_ptr
(C++11),
std::auto_ptr
, and raw pointers. Plus, ODB profile
libraries, that available for commonly used frameworks and libraries
(such as Boost and Qt), provide support for smart pointers found in these
@@ -5385,13 +5430,20 @@ t.commit ();
access it.
The ODB runtime library provides lazy counterparts for all the
- supported pointers, namely: odb::lazy_shared_ptr
and
- odb::lazy_weak_ptr
for TR1 shared_ptr
and
- weak_ptr
, odb::lazy_auto_ptr
for
- std::auto_ptr
, and odb::lazy_ptr
for raw
- pointers. The ODB profile libraries provide lazy pointer
- implementations for smart pointers from popular frameworks and
- libraries (Part III, "Profiles").
odb::lazy_shared_ptr
/lazy_weak_ptr
+ for C++11 std::shared_ptr
/weak_ptr
,
+ odb::tr1::lazy_shared_ptr
/lazy_weak_ptr
+ for TR1 std::tr1::shared_ptr
/weak_ptr
,
+ odb::lazy_unique_ptr
for C++11 std::unique_ptr
,
+ odb::lazy_auto_ptr
for std::auto_ptr
,
+ and odb::lazy_ptr
for raw pointers. The TR1 lazy
+ pointers are defined in the <odb/tr1/lazy-ptr.hxx>
+ header while all the others — in
+ <odb/lazy-ptr.hxx>
. The ODB profile
+ libraries also provide lazy pointer implementations for smart pointers
+ from popular frameworks and libraries (Part III,
+ "Profiles").
While we will discuss the interface of lazy pointers in more detail shortly, the most commonly used extra function provided by these @@ -5507,6 +5559,7 @@ public: // Query object id and database of a persistent object. // template <class O /* = T */> + // C++11: template <class O = T> object_traits<O>::id_type object_id () const; odb::database& database () const; @@ -5536,6 +5589,7 @@ for (employees::iterator i (es.begin ()); i != es.end (); ++i) lazy_weak_ptr<employee>& lwp (*i); if (lwp.object_id<employee> () < 100) + // C++11: if (lwp.object_id () < 100) { shared_ptr<employee> e (lwp.load ()); // Load and lock. cout << e->first_ << " " << e->last_ << endl; @@ -6240,8 +6294,9 @@ class person
The ODB compiler includes built-in support for using
- std::auto_ptr
and std::tr1::shared_ptr
- as pointers to values. Plus, ODB profile libraries, that are
+ std::auto_ptr
, std::unique_ptr
(C++11),
+ and shared_ptr
(TR1 or C++11) as pointers to values.
+ Plus, ODB profile libraries, that are
available for commonly used frameworks and libraries (such as Boost and
Qt), provide support for smart pointers found in these frameworks
and libraries (Part III, "Profiles").
The per-object caching policies depend on the object pointer kind
(Section 6.4, "Using Custom Smart Pointers").
- Objects with a unique pointer, such as std::auto_ptr
,
- as an object pointer are never cached since it is not possible to have
- two such pointers pointing to the same object. When an object is
- persisted via a pointer or loaded as a dynamically allocated instance,
- objects with both raw and shared pointers as object pointers are
- cached. If an object is persisted as a reference or loaded into
- a pre-allocated instance, the object is only cached if its object
- pointer is a raw pointer.
std::auto_ptr
+ or std::unique_ptr
, as an object pointer are never
+ cached since it is not possible to have two such pointers pointing
+ to the same object. When an object is persisted via a pointer or
+ loaded as a dynamically allocated instance, objects with both raw
+ and shared pointers as object pointers are cached. If an object is
+ persisted as a reference or loaded into a pre-allocated instance,
+ the object is only cached if its object pointer is a raw pointer.
Also note that when we persist an object as a constant reference or constant pointer, the session caches such an object as @@ -11042,7 +11097,7 @@ namespace odb const char* socket = 0, const char* charset = 0, unsigned long client_flags = 0, - std::auto_ptr<connection_factory> = 0); + std::[auto|unique]_ptr<connection_factory> = 0); database (const std::string& user, const std::string& passwd, @@ -11052,7 +11107,7 @@ namespace odb const std::string* socket = 0, const std::string& charset = "", unsigned long client_flags = 0, - std::auto_ptr<connection_factory> = 0); + std::[auto|unique]_ptr<connection_factory> = 0); database (const std::string& user, const std::string* passwd, @@ -11062,7 +11117,7 @@ namespace odb const std::string* socket = 0, const std::string& charset = "", unsigned long client_flags = 0, - std::auto_ptr<connection_factory> = 0); + std::[auto|unique]_ptr<connection_factory> = 0); database (const std::string& user, const std::string& passwd, @@ -11072,7 +11127,7 @@ namespace odb const std::string& socket, const std::string& charset = "", unsigned long client_flags = 0, - std::auto_ptr<connection_factory> = 0); + std::[auto|unique]_ptr<connection_factory> = 0); database (const std::string& user, const std::string* passwd, @@ -11082,14 +11137,14 @@ namespace odb const std::string& socket, const std::string& charset = "", unsigned long client_flags = 0, - std::auto_ptr<connection_factory> = 0); + std::[auto|unique]_ptr<connection_factory> = 0); database (int& argc, char* argv[], bool erase = false, const std::string& charset = "", unsigned long client_flags = 0, - std::auto_ptr<connection_factory> = 0); + std::[auto|unique]_ptr<connection_factory> = 0); static void print_usage (std::ostream&); @@ -11188,12 +11243,12 @@ namespace odb
The static print_usage()
function prints the list of options
with short descriptions that are recognized by this constructor.
The last argument to all of the constructors is a
- pointer to the connection factory. If we pass a
- non-NULL
value, the database instance assumes
- ownership of the factory instance. The connection factory
- interface as well as the available implementations are described
- in the next section.
The last argument to all of the constructors is a pointer to the
+ connection factory. In C++98, it is std::auto_ptr
while
+ in C++11 std::unique_ptr
is used instead. If we pass a
+ non-NULL
value, the database instance assumes ownership
+ of the factory instance. The connection factory interface as well as
+ the available implementations are described in the next section.
The set of accessor functions following the constructors allows us
to query the parameters of the database
instance.
The static print_usage()
function prints the list of options
with short descriptions that are recognized by the second constructor.
The last argument to both constructors is a pointer to the connection
- factory. If we pass a non-NULL
value, the database instance
- assumes ownership of the factory instance. The connection factory
- interface as well as the available implementations are described
- in the next section.
The last argument to all of the constructors is a pointer to the
+ connection factory. In C++98, it is std::auto_ptr
while
+ in C++11 std::unique_ptr
is used instead. If we pass a
+ non-NULL
value, the database instance assumes ownership
+ of the factory instance. The connection factory interface as well as
+ the available implementations are described in the next section.
The set of accessor functions following the constructors allows us
to query the parameters of the database
instance.
The last argument to all of the constructors is a pointer to the
- connection factory. If we pass a non-NULL
value, the
- database instance assumes ownership of the factory instance. The
- connection factory interface as well as the available implementations
- are described in the next section.
std::auto_ptr
while
+ in C++11 std::unique_ptr
is used instead. If we pass a
+ non-NULL
value, the database instance assumes ownership
+ of the factory instance. The connection factory interface as well as
+ the available implementations are described in the next section.
The set of accessor functions following the constructors allows us
to query the parameters of the database
instance. Note that
@@ -13033,7 +13090,7 @@ namespace odb
ub2 charset = 0,
ub2 ncharset = 0,
OCIEnv* environment = 0,
- std::auto_ptr<connection_factory> = 0);
+ std::[auto|unique]_ptr<connection_factory> = 0);
database (const std::string& user,
const std::string& password,
@@ -13043,7 +13100,7 @@ namespace odb
ub2 charset = 0,
ub2 ncharset = 0,
OCIEnv* environment = 0,
- std::auto_ptr<connection_factory> = 0);
+ std::[auto|unique]_ptr<connection_factory> = 0);
database (int& argc,
char* argv[],
@@ -13051,7 +13108,7 @@ namespace odb
ub2 charset = 0,
ub2 ncharset = 0,
OCIEnv* environment = 0,
- std::auto_ptr<connection_factory> = 0);
+ std::[auto|unique]_ptr<connection_factory> = 0);
static void
print_usage (std::ostream&);
@@ -13174,11 +13231,12 @@ namespace odb
environment handle is used, then the charset
and
ncharset
arguments have no effect.
The last argument to all of the constructors is a pointer to a
- connection factory. If we pass a non-NULL
value, the
- database instance assumes ownership of the factory instance. The
- connection factory interface as well as the available implementations
- are described in the next section.
The last argument to all of the constructors is a pointer to the
+ connection factory. In C++98, it is std::auto_ptr
while
+ in C++11 std::unique_ptr
is used instead. If we pass a
+ non-NULL
value, the database instance assumes ownership
+ of the factory instance. The connection factory interface as well as
+ the available implementations are described in the next section.
The set of accessor functions following the constructors allows us
to query the parameters of the database
instance.
database
instance.
- The last argument to all of the constructors is a pointer to a
- connection factory. If we pass a non-NULL
value, the
- database instance assumes ownership of the factory instance. The
- connection factory interface as well as the available implementations
- are described in the next section.
The last argument to all of the constructors is a pointer to the
+ connection factory. In C++98, it is std::auto_ptr
while
+ in C++11 std::unique_ptr
is used instead. If we pass a
+ non-NULL
value, the database instance assumes ownership
+ of the factory instance. The connection factory interface as well as
+ the available implementations are described in the next section.
The set of accessor functions following the constructors allows us
to query the parameters of the database
instance.