1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Object Life Time and Persistence</title>
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
<meta name="generator" content="DocBook XSL Stylesheets V1.73.2" />
<link rel="start" href="index.html" title="Berkeley DB Programmer's Reference Guide" />
<link rel="up" href="stl_persistence.html" title="Dbstl Persistence" />
<link rel="prev" href="section2.html" title="Change Persistence" />
<link rel="next" href="stl_container_specific.html" title="Dbstl Container Specific Notes" />
</head>
<body>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr>
<th colspan="3" align="center">Object Life Time and Persistence </th>
</tr>
<tr>
<td width="20%" align="left"><a accesskey="p" href="section2.html">Prev</a> </td>
<th width="60%" align="center">Dbstl Persistence</th>
<td width="20%" align="right"> <a accesskey="n" href="stl_container_specific.html">Next</a></td>
</tr>
</table>
<hr />
</div>
<div class="section" lang="en" xml:lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both"><a id="section3"></a>Object Life Time and Persistence </h2>
</div>
</div>
</div>
<p>
</p>
<pre class="programlisting">
class ID
{
public:
string Name;
int Score;
};
</pre>
<p>
</p>
<p>
Dbstl is an interface to Berkeley DB, so it is used to store data
persistently. This is really a different purpose from that of regular
c++ STL. This difference in their aims has an implication to object
lifetime: In standard STL, when you store an object A of type ID into
C++ stl vector V via V.push_back(A), if a proper copy constructor is
provided in A's class type, then the copy of A (call it B) and
everything in B, such as another object C pointed to by B's data
member B.c_ptr, will be stored in V and will live as long as B is
still in V and V is alive. B will be destroyed when V is destroyed
or B is erased from V.
</p>
<p>
This is not true for dbstl, which will copy A's data and store it into
the underlying database. The copy is by default a shallow copy, but
users can register their object marshalling and unmarshalling
functions via the DbstlElemTraits class template. So if A is passed
to a db_vector container dv via dV.push_back(A), then we will copy A's
data using the registered functions, and store the chunk of bytes into
the underlying database. So A will be valid, even if the container is
destroyed, because it is stored into the database.
If the copy is simply a shallow copy, and A is later destroyed, then
the pointer stored in the database will become invalid, and the next
time we use the retrieved object, we would be using an invalid
pointer, thus there will be errors. The way to avoid this is to store
the referred object C rather than the pointer member A.c_ptr itself,
by registering the right marshalling/unmarshalling function with
DbstlElemTraits.
</p>
<p>
In the above example, the class ID has a data member Name, which will
refer to a memory address of the actual characters in the string. If
we simply shallow copy an object id of class ID to store it, then the
stored data idd will be invalid when id is destroyed. This is because
idd and id refer to a common memory address which is the base address
of the memory space storing all characters in the string, and this
memory space is released when id is destroyed. So idd will be
refering an invalid address, and the next time we retrieve idd and use
it, there will be memory corruption.
</p>
<p>
The right way to store id is to write a marshall/unmarshal function
pair like this:
</p>
<p>
</p>
<pre class="programlisting">
void copy_id(void *dest, const ID&elem)
{
memcpy(dest, &elem.Score, sizeof(elem.Score));
char *p = ((char *)dest) + sizeof(elem.Score);
strcpy(p, elem.Name.c_str());
}
void restore_id(ID& dest, const void *srcdata)
{
memcpy(&dest.Score, srcdata, sizeof(dest.Score));
const char *p = ((char *)srcdata) + sizeof(dest.Score);
dest.Name = p;
}
size_t size_id(const ID& elem)
{
return sizeof(elem.Score) + elem.Name.size() +
1;// store the '\0' char.
}
</pre>
<p>
</p>
<p>
Then register the above functions before storing any instance of ID:
</p>
<p>
</p>
<pre class="programlisting">
DbstlElemTraits<ID>::instance()->set_copy_function(copy_id);
DbstlElemTraits<ID>::instance()->set_size_function(size_id);
DbstlElemTraits<ID>::instance()->set_restore_function(restore_id);
</pre>
<p>
</p>
<p>
This way, the actual data of instances of ID are stored, thus the data will persist even if the container itself is destroyed.
</p>
</div>
<div class="navfooter">
<hr />
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left"><a accesskey="p" href="section2.html">Prev</a> </td>
<td width="20%" align="center">
<a accesskey="u" href="stl_persistence.html">Up</a>
</td>
<td width="40%" align="right"> <a accesskey="n" href="stl_container_specific.html">Next</a></td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Change Persistence </td>
<td width="20%" align="center">
<a accesskey="h" href="index.html">Home</a>
</td>
<td width="40%" align="right" valign="top"> Dbstl Container Specific Notes</td>
</tr>
</table>
</div>
</body>
</html>
|