1. Explanation
The following library is used for design patterns.
- Helps with many of the same objects in a program and requires reduced memory consumption.
- Boost.Signals2 makes it easy to use observer design patterns. This library is called Boost.Signals2 because it implements the concept of signal/slot.
- Making it possible to transfer state machines from UML to C++.
Contents of this section
66.
67. Boost.Signals2
68.
2. Library
It is a library that can easily use the same-name design pattern. When many objects share data, enjoying the world helps save memory. Using this design pattern, instead of storing the same data multiple times in an object, the shared data is saved in one place, and all objects refer to that data. While you can implement this design pattern using, for example, pointers, it is easier to use.
Example 66.1. There are hundreds of thousands of identical strings without
#include <string> #include <vector> struct person { int id_; std::string city_; }; int main() { std::vector<person> persons; for (int i = 0; i < 100000; ++i) persons.push_back({i, "Berlin"}); }
Example 66.1
Example 66.1 Created 100,000 objects of type person. person defines two member variables: id_identifies people, and city_ stores the city where people live. In this example, everyone lives in Berlin. This is why city_ is set to "Berlin" in all 100,000 objects. Therefore, this example uses a hundred thousand strings, all of which are set to the same value. Using , you can use a string—not thousands—and reduce memory consumption.
Example 66.2. Use one string instead of one hundred thousand strings
#include <boost/> #include <string> #include <vector> #include <utility> using namespace boost::flyweights; struct person { int id_; flyweight<std::string> city_; person(int id, std::string city) : id_{id}, city_{std::move(city)} {} }; int main() { std::vector<person> persons; for (int i = 0; i < 100000; ++i) persons.push_back({i, "Berlin"}); }
To use , include boost/, as shown in Example 66.2. Additional headers are provided, which are only required to include when you need to change detailed library settings.
All classes and functions are in the namespace boost::flyweights . Example 66.2 Use only the class boost::flyweights::flyweight, which is the most important class in the library. Member variable city_ uses the type flyweight<std::string> instead of std::string. Here is everything you need to change to use this design pattern and reduce the memory requirements of your program.
Example 66.3. Use boost::flyweights::flyweights
#include <boost/> #include <string> #include <vector> #include <utility> using namespace boost::flyweights; struct person { int id_; flyweight<std::string> city_; flyweight<std::string> country_; person(int id, std::string city, std::string country) : id_{id}, city_{std::move(city)}, country_{std::move(country)} {} }; int main() { std::vector<person> persons; for (int i = 0; i < 100000; ++i) persons.push_back({i, "Berlin", "Germany"}); }
Example 66.3
Example 66.3 Added the second member variable country_ to the class person. This member variable contains the name of the country in which people live. Because in this case, everyone lives in Berlin, they all live in the same country. This is why boost::flyweights::flyweights::flyweight is also used in the definition of the member variable country_ .
Use an internal container to store objects. It ensures that there cannot be multiple objects with the same value. By default, a hash container is used, such as std::unordered_set. For different types, use different hash containers. Like Example 66.3, the member variables city_ and country_ are both strings; therefore, only one container is used. In this example, this is not a problem, because the container stores only two strings: "Berlin" and "Germany". If many different cities and countries have to be stored, it is best to store the city in one container and the country in another.
Example 66.4. Use boost::flyweights::flyweight tags multiple times
#include <boost/> #include <string> #include <vector> #include <utility> using namespace boost::flyweights; struct city {}; struct country {}; struct person { int id_; flyweight<std::string, tag<city>> city_; flyweight<std::string, tag<country>> country_; person(int id, std::string city, std::string country) : id_{id}, city_{std::move(city)}, country_{std::move(country)} {} }; int main() { std::vector<person> persons; for (int i = 0; i < 100000; ++i) persons.push_back({i, "Berlin", "Germany"}); }
Example 66.4 Pass the second template parameter to boost::flyweights::flyweight. This is a tag. Tags are any type and are only used to distinguish between the types on which city_ and country_ are based. Example 66.4 defines two empty structure cities and countries to be used as labels. However, the example can be used instead with int, bool, or any type.
Tags make city_ and country_ use different types. Two hash containers are now used - one stores the city and the other stores the country.
Example 66.5. The template parameters of boost::flyweights::flyweight
#include <boost/> #include <boost/flyweight/set_factory.hpp> #include <boost/flyweight/no_locking.hpp> #include <boost/flyweight/no_tracking.hpp> #include <string> #include <vector> #include <utility> using namespace boost::flyweights; struct person { int id_; flyweight<std::string, set_factory<>, no_locking, no_tracking> city_; person(int id, std::string city) : id_{id}, city_{std::move(city)} {} }; int main() { std::vector<person> persons; for (int i = 0; i < 100000; ++i) persons.push_back({i, "Berlin"}); }
Template parameters other than tags can be passed to boost::flyweights::flyweight. Example 66.5 via boost::flyweights::set_factory, boost::flyweights::no_locking, and boost::flyweights::no_tracking. Includes additional header files to use these classes.
boost::flyweights::set_factory tells to use sort containers, such as std::set, instead of hash containers. Using boost::flyweights::no_locking, support for multithreads that are normally activated by default is deactivated. boost::flyweights::no_tracking Tell Do not track objects stored in the internal container. By default, when objects are no longer used, this is detected and removed from the container. When boost::flyweights::no_tracking is set, the detection mechanism is disabled. This improves performance. However, containers can only grow and never shrink.
Supports additional settings. If you are interested in more details of the adjustment, please check out the official documentation.
Practice
Use to improve this program. Use disable multithreading support:
#include <string> #include <vector> #include <memory> int main() { std::vector<std::shared_ptr<std::string>> countries; auto germany = std::make_shared<std::string>("Germany"); for (int i = 0; i < 500; ++i) countries.push_back(germany); auto netherlands = std::make_shared<std::string>("Netherlands"); for (int i = 0; i < 500; ++i) countries.push_back(netherlands); }
This is the article about the introduction to the use of the C++ Boost Flyweight library. For more related C++ Boost Flyweight content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!