| <!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></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> |
| |
| <h3><a name="requirements">Flyweight requirements</a></h3> |
| |
| <p> |
| For <code>flyweight<T></code> to be instantiable, <code>T</code> must |
| be <a href="http://www.sgi.com/tech/stl/Assignable.html"><code>Assignable</code></a>, |
| <a href="http://www.sgi.com/tech/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 December 2nd 2008</p> |
| |
| <p>© Copyright 2006-2008 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> |