C++ Boost Flyweight库使用介绍
作者:无水先生
一、说明
以下库用于设计模式。
- Boost.Flyweight 有助于在程序中使用许多相同的对象并且需要减少内存消耗的情况。
- Boost.Signals2 使得使用观察者设计模式变得容易。这个库被称为 Boost.Signals2 因为它实现了信号/槽的概念。
- Boost.MetaStateMachine 使得将状态机从 UML 转移到 C++ 成为可能。
本节内容
二、库Boost.Flyweight
Boost.Flyweight 是一个可以轻松使用同名设计模式的库。当许多对象共享数据时,享元有助于节省内存。使用这种设计模式,不是在对象中多次存储相同的数据,而是将共享数据保存在一个地方,所有对象都引用该数据。虽然您可以使用例如指针来实现此设计模式,但使用 Boost.Flyweight 更容易。
示例 66.1。没有 Boost.Flyweight 的十万个相同的字符串
#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"}); }
示例 66.1 创建了十万个 person 类型的对象。 person 定义了两个成员变量:id_ 标识人,city_ 存储人们居住的城市。在这个例子中,所有人都住在柏林。这就是为什么 city_ 在所有十万个对象中都设置为“Berlin”。因此,该示例使用十万个字符串,所有字符串都设置为相同的值。使用 Boost.Flyweight,可以使用一个字符串——而不是数千个——并且可以减少内存消耗。
示例 66.2。使用 Boost.Flyweight 一个字符串而不是十万个字符串
#include <boost/flyweight.hpp> #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"}); }
要使用 Boost.Flyweight,请包含 boost/flyweight.hpp,如示例 66.2 所示。 Boost.Flyweight 提供了额外的头文件,仅当您需要更改详细的库设置时才需要包含这些头文件。
所有类和函数都在命名空间 boost::flyweights 中。示例 66.2 仅使用类 boost::flyweights::flyweight,这是该库中最重要的类。成员变量 city_ 使用类型 flyweight<std::string> 而不是 std::string。这是您需要更改的所有内容,以使用此设计模式并减少程序的内存需求。
示例 66.3。多次使用 boost::flyweights::flyweight
#include <boost/flyweight.hpp> #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"}); }
示例 66.3 向类 person 添加了第二个成员变量 country_。这个成员变量包含人们居住的国家的名字。因为在这个例子中,所有人都住在柏林,所以他们都住在同一个国家。这就是为什么在成员变量 country_ 的定义中也使用了 boost::flyweights::flyweight。
Boost.Flyweight 使用一个内部容器来存储对象。它确保不能有多个具有相同值的对象。默认情况下,Boost.Flyweight 使用哈希容器,例如 std::unordered_set。对于不同的类型,使用不同的散列容器。与示例 66.3 一样,成员变量 city_ 和 country_ 都是字符串;因此,只使用一个容器。在此示例中,这不是问题,因为容器仅存储两个字符串:“Berlin”和“Germany”。如果必须存储许多不同的城市和国家,最好将城市存储在一个容器中,将国家存储在另一个容器中。
示例 66.4。多次使用 boost::flyweights::flyweight 标签
#include <boost/flyweight.hpp> #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"}); }
示例 66.4 将第二个模板参数传递给 boost::flyweights::flyweight。这是一个标签。标签是任意类型,仅用于区分 city_ 和 country_ 所基于的类型。示例 66.4 定义了两个空结构城市和国家,用作标签。但是,该示例可以改为使用 int、bool 或任何类型。
标签使 city_ 和 country_ 使用不同的类型。现在 Boost.Flyweight 使用了两个哈希容器——一个存储城市,另一个存储国家。
示例 66.5。 boost::flyweights::flyweight 的模板参数
#include <boost/flyweight.hpp> #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"}); }
标签以外的模板参数可以传递给 boost::flyweights::flyweight。示例 66.5 通过 boost::flyweights::set_factory、boost::flyweights::no_locking 和 boost::flyweights::no_tracking。包含额外的头文件以使用这些类。
boost::flyweights::set_factory 告诉 Boost.Flyweight 使用排序容器,例如 std::set,而不是散列容器。使用 boost::flyweights::no_locking,通常默认激活的对多线程的支持被停用。 boost::flyweights::no_tracking 告诉 Boost.Flyweight 不要跟踪存储在内部容器中的对象。默认情况下,当不再使用对象时,Boost.Flyweight 会检测到这一点并将它们从容器中移除。当设置了 boost::flyweights::no_tracking 时,检测机制被禁用。这提高了性能。但是,容器只能增长,永远不会收缩。
Boost.Flyweight 支持额外的设置。如果您对调整的更多细节感兴趣,请查看官方文档。
炼习
使用 Boost.Flyweight 改进这个程序。使用禁用多线程支持的 Boost.Flyweight:
#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); }
到此这篇关于C++ Boost Flyweight库使用介绍的文章就介绍到这了,更多相关C++ Boost Flyweight内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!