123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>Boost.Flyweight Documentation - Tutorial - Basics</title>
- <link rel="stylesheet" href="../style.css" type="text/css">
- <link rel="start" href="../index.html">
- <link rel="prev" href="index.html">
- <link rel="up" href="index.html">
- <link rel="next" href="key_value.html">
- </head>
- <body>
- <h1><img src="../../../../boost.png" alt="Boost logo" align=
- "middle" width="277" height="86">Boost.Flyweight Tutorial: Basics</h1>
- <div class="prev_link"><a href="index.html"><img src="../prev.gif" alt="Boost.Flyweight tutorial" border="0"><br>
- Boost.Flyweight tutorial
- </a></div>
- <div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.Flyweight tutorial" border="0"><br>
- Boost.Flyweight tutorial
- </a></div>
- <div class="next_link"><a href="key_value.html"><img src="../next.gif" alt="key-value flyweights" border="0"><br>
- Key-value flyweights
- </a></div><br clear="all" style="clear: all;">
- <hr>
- <h2>Contents</h2>
- <ul>
- <li><a href="#intro">Introduction</a>
- <ul>
- <li><a href="#serialization">Serialization</a></li>
- </ul>
- </li>
- <li><a href="#requirements">Flyweight requirements</a></li>
- </ul>
- <h2><a name="intro">Introduction</a></h2>
- <p>
- Suppose we are writing a massive multiplayer online game
- which has to maintain hundreds of thousands or millions of instances
- of the following class in memory:
- </p>
- <blockquote><pre>
- <span class=keyword>struct</span> <span class=identifier>user_entry</span>
- <span class=special>{</span>
- <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>first_name</span><span class=special>;</span>
- <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>last_name</span><span class=special>;</span>
- <span class=keyword>int</span> <span class=identifier>age</span><span class=special>;</span>
- <span class=special>...</span>
- <span class=special>};</span>
- </pre></blockquote>
- <p>
- In this kind of environments memory resources are precious, so we are seeking
- ways to make <code>user_entry</code> as compact as possible. Typically, there
- exists a very high level of repetition of first and last names among
- the community users, so an obvious optimization consists in moving
- <code>user_entry::first_name</code> and <code>user_entry::last_name</code>
- objects to a common repository where duplicates are avoided, and leaving
- references to these inside <code>user_entry</code>. This is precisely what
- Boost.Flyweight does in the simplest possible way for the programmer:
- </p>
- <blockquote><pre>
- <span class=preprocessor>#include</span> <span class=special><</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>flyweight</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>></span>
- <span class=keyword>struct</span> <span class=identifier>user_entry</span>
- <span class=special>{</span>
- <span class=identifier>flyweight</span><span class=special><</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>></span> <span class=identifier>first_name</span><span class=special>;</span>
- <span class=identifier>flyweight</span><span class=special><</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>></span> <span class=identifier>last_name</span><span class=special>;</span>
- <span class=keyword>int</span> <span class=identifier>age</span><span class=special>;</span>
- <span class=special>...</span>
- <span class=special>};</span>
- </pre></blockquote>
- <p>
- Boost.Flyweight automatically performs the optimization just described behind
- the scenes, so that the net effect of this change is that the memory
- usage of the program decreases by a factor proportional to the level of
- redundancy among user names.
- </p>
- <p>
- <code>flyweight<std::string></code> behaves in many ways like
- <code>std::string</code>; for instance, the following code works
- unchanged after the redefinition of <code>user_entry</code>:
- </p>
- <blockquote><pre>
- <span class=comment>// flyweight<T> can be constructed in the same way as T objects can,
- // even with multiple argument constructors</span>
- <span class=identifier>user_entry</span><span class=special>::</span><span class=identifier>user_entry</span><span class=special>(</span><span class=keyword>const</span> <span class=keyword>char</span><span class=special>*</span> <span class=identifier>f</span><span class=special>,</span><span class=keyword>const</span> <span class=keyword>char</span><span class=special>*</span> <span class=identifier>l</span><span class=special>,</span><span class=keyword>int</span> <span class=identifier>a</span><span class=special>,...):</span>
- <span class=identifier>first_name</span><span class=special>(</span><span class=identifier>f</span><span class=special>),</span>
- <span class=identifier>last_name</span><span class=special>(</span><span class=identifier>l</span><span class=special>),</span>
- <span class=identifier>age</span><span class=special>(</span><span class=identifier>a</span><span class=special>),</span>
- <span class=special>...</span>
- <span class=special>{}</span>
- <span class=comment>// flyweight classes have relational operators replicating the
- // semantics of the underyling type</span>
- <span class=keyword>bool</span> <span class=identifier>same_name</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>user_entry</span><span class=special>&</span> <span class=identifier>user1</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>user_entry</span><span class=special>&</span> <span class=identifier>user2</span><span class=special>)</span>
- <span class=special>{</span>
- <span class=keyword>return</span> <span class=identifier>user1</span><span class=special>.</span><span class=identifier>first_name</span><span class=special>==</span><span class=identifier>user2</span><span class=special>.</span><span class=identifier>first_name</span> <span class=special>&&</span>
- <span class=identifier>user1</span><span class=special>.</span><span class=identifier>last_name</span><span class=special>==</span><span class=identifier>user2</span><span class=special>.</span><span class=identifier>last_name</span><span class=special>;</span>
- <span class=special>}</span>
- <span class=comment>// flyweight<T> provides operator<< and operator>> internally
- // forwarding to T::operator<< and T::operator>></span>
- <span class=identifier>std</span><span class=special>::</span><span class=identifier>ostream</span><span class=special>&</span> <span class=keyword>operator</span><span class=special><<(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>ostream</span><span class=special>&</span> <span class=identifier>os</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>user_entry</span><span class=special>&</span> <span class=identifier>user</span><span class=special>)</span>
- <span class=special>{</span>
- <span class=keyword>return</span> <span class=identifier>os</span><span class=special><<</span><span class=identifier>user</span><span class=special>.</span><span class=identifier>first_name</span><span class=special><<</span><span class=string>" "</span><span class=special><<</span><span class=identifier>user</span><span class=special>.</span><span class=identifier>last_name</span><span class=special><<</span><span class=string>" "</span><span class=special><<</span><span class=identifier>user</span><span class=special>.</span><span class=identifier>age</span><span class=special>;</span>
- <span class=special>}</span>
- <span class=identifier>std</span><span class=special>::</span><span class=identifier>istream</span><span class=special>&</span> <span class=keyword>operator</span><span class=special>>>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>istream</span><span class=special>&</span> <span class=identifier>is</span><span class=special>,</span><span class=identifier>user_entry</span><span class=special>&</span> <span class=identifier>user</span><span class=special>)</span>
- <span class=special>{</span>
- <span class=keyword>return</span> <span class=identifier>is</span><span class=special>>></span><span class=identifier>user</span><span class=special>.</span><span class=identifier>first_name</span><span class=special>>></span><span class=identifier>user</span><span class=special>.</span><span class=identifier>last_name</span><span class=special>>></span><span class=identifier>user</span><span class=special>.</span><span class=identifier>age</span><span class=special>;</span>
- <span class=special>}</span>
- </pre></blockquote>
- <p>
- Besides, <code>flyweight<T></code> is convertible to
- <code>const T&</code>, either implicitly or through the <code>get</code>
- member function:
- </p>
- <blockquote><pre>
- <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>full_name</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>user_entry</span><span class=special>&</span> <span class=identifier>user</span><span class=special>)</span>
- <span class=special>{</span>
- <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span> <span class=identifier>full</span><span class=special>;</span>
- <span class=identifier>full</span><span class=special>.</span><span class=identifier>reserve</span><span class=special>(</span>
- <span class=identifier>user</span><span class=special>.</span><span class=identifier>first_name</span><span class=special>.</span><span class=identifier>get</span><span class=special>().</span><span class=identifier>size</span><span class=special>()+</span> <span class=comment>// get() returns the underlying</span>
- <span class=identifier>user</span><span class=special>.</span><span class=identifier>last_name</span><span class=special>.</span><span class=identifier>get</span><span class=special>().</span><span class=identifier>size</span><span class=special>()+</span><span class=number>1</span><span class=special>);</span> <span class=comment>// const std::string&</span>
- <span class=identifier>full</span><span class=special>+=</span><span class=identifier>user</span><span class=special>.</span><span class=identifier>first_name</span><span class=special>;</span> <span class=comment>// implicit conversion is used here</span>
- <span class=identifier>full</span><span class=special>+=</span><span class=string>" "</span><span class=special>;</span>
- <span class=identifier>full</span><span class=special>+=</span><span class=identifier>user</span><span class=special>.</span><span class=identifier>last_name</span><span class=special>;</span>
- <span class=keyword>return</span> <span class=identifier>full</span><span class=special>;</span>
- <span class=special>}</span>
- </pre></blockquote>
- <p>
- The most important restriction to take into account when replacing a class
- with an equivalent flyweight is the fact that flyweights are not
- mutable: since several flyweight objects can share the same representation
- value, modifying this value is not admissible. On the other hand, flyweight
- objects can be assigned new values:
- </p>
- <blockquote><pre>
- <span class=keyword>void</span> <span class=identifier>change_name</span><span class=special>(</span>
- <span class=identifier>user_entry</span><span class=special>&</span> <span class=identifier>user</span><span class=special>,</span>
- <span class=keyword>const</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&</span> <span class=identifier>f</span><span class=special>,</span><span class=keyword>const</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&</span> <span class=identifier>l</span><span class=special>)</span>
- <span class=special>{</span>
- <span class=identifier>user</span><span class=special>.</span><span class=identifier>first_name</span><span class=special>=</span><span class=identifier>f</span><span class=special>;</span>
- <span class=identifier>user</span><span class=special>.</span><span class=identifier>last_name</span><span class=special>=</span><span class=identifier>l</span><span class=special>;</span>
- <span class=special>}</span>
- </pre></blockquote>
- <p>
- In general, <code>flyweight<T></code> interface is designed to make
- the transition from plain <code>T</code> as straightforward as possible.
- Check the <a href="../reference/flyweight.html#flyweight">reference</a> for
- further details on the interface of the class template <code>flyweight</code>.
- The <a href="../examples.html">examples section</a> explores
- some common usage scenarios of Boost.Flyweight.
- </p>
- <h4><a name="serialization">Serialization</a></h4>
- <p>
- <code>flyweight<T></code> can be serialized by means of the
- <a href="../../../serialization/index.html">Boost Serialization Library</a>
- as long as the underlying <code>T</code> is serializable. Both regular and
- XML archives are supported. In order to
- use Boost.Flyweight serialization capabilities, the specific
- header <a href="../reference/flyweight.html#serialize_synopsis"><code>"boost/flyweight/serialize.hpp"</code></a>
- must be included.
- </p>
- <blockquote><pre><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">flyweight</span><span class="special">/</span><span class="identifier">serialize</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
- <span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">Archive</span><span class="special">></span>
- <span class="keyword">void</span> <span class="identifier">serialize</span><span class="special">(</span><span class="identifier">Archive</span><span class="special">&</span> <span class="identifier">ar</span><span class="special">,</span><span class="identifier">user_entry</span><span class="special">&</span> <span class="identifier">user</span><span class="special">,</span><span class="keyword">const</span> <span class="keyword">unsigned</span> <span class="keyword">int</span><span class="special">)</span>
- <span class="special">{</span>
- <span class="identifier">ar</span><span class="special">&</span><span class="identifier">user</span><span class="special">.</span><span class="identifier">first_name</span><span class="special">;</span>
- <span class="identifier">ar</span><span class="special">&</span><span class="identifier">user</span><span class="special">.</span><span class="identifier">last_name</span><span class="special">;</span>
- <span class="identifier">ar</span><span class="special">&</span><span class="identifier">user</span><span class="special">.</span><span class="identifier">age</span><span class="special">;</span>
- <span class="special">...</span>
- <span class="special">}</span>
- </pre></blockquote>
-
- <p>
- Much as using Boost.Flyweight reduces memory consumption due to the internal
- sharing of duplicate values, serializing <code>flyweight</code>s can also
- result in smaller archive files, as a common value is only stored
- once and their associated <code>flyweight</code>s get saved as references to it.
- This policy is observed even if <code>flyweight</code> underlying type is
- not <a href="../../../serialization/doc/traits.html#tracking">tracked</a>
- by Boost.Serialization.
- </p>
- <p>
- See <a href="../examples.html#example6">example 6</a> at the examples section
- for an illustration of use of Boost.Flyweight serialization capabilities.
- </p>
- <h3><a name="requirements">Flyweight requirements</a></h3>
- <p>
- For <code>flyweight<T></code> to be instantiable, <code>T</code> must
- be <a href="https://boost.org/sgi/stl/Assignable.html"><code>Assignable</code></a>,
- <a href="https://boost.org/sgi/stl/EqualityComparable.html"><code>Equality
- Comparable</code></a> and must interoperate with
- <a href="../../../functional/hash/index.html">Boost.Hash</a>.
- The first requirement is probably met without any extra effort by the user,
- not so the other two, except for the most common basic types of C++
- and the standard library. Equality and hashing of <code>T</code> are used
- internally by <code>flyweight<T></code> internal factory to maintain the
- common repository of unique <code>T</code> values referred to by the flyweight
- objects. Consult the Boost.Hash documentation
- <a href="../../../../doc/html/hash/custom.html">section</a> on extending
- that library for custom data types.
- </p>
- <p>
- As we have seen, equality and hash requirements on <code>T</code> are
- imposed by the particular type of <i>flyweight factory</i> internally used by
- <code>flyweight<T></code>. We will see later how the user can customize
- this factory to use equality and hash predicates other than the default,
- or even switch to an entirely different kind of factory which may impose
- another requirements on <code>T</code>, as described in the section on
- <a href="configuration.html">configuring Boost.Flyweight</a>.
- </p>
- <hr>
- <div class="prev_link"><a href="index.html"><img src="../prev.gif" alt="Boost.Flyweight tutorial" border="0"><br>
- Boost.Flyweight tutorial
- </a></div>
- <div class="up_link"><a href="index.html"><img src="../up.gif" alt="Boost.Flyweight tutorial" border="0"><br>
- Boost.Flyweight tutorial
- </a></div>
- <div class="next_link"><a href="key_value.html"><img src="../next.gif" alt="key-value flyweights" border="0"><br>
- Key-value flyweights
- </a></div><br clear="all" style="clear: all;">
- <br>
- <p>Revised April 24th 2019</p>
- <p>© Copyright 2006-2019 Joaquín M López Muñoz.
- Distributed under the Boost Software
- License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt">
- LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
- http://www.boost.org/LICENSE_1_0.txt</a>)
- </p>
- </body>
- </html>
|