亲宝软件园·资讯

展开

C++ Boost Flyweight库使用介绍

无水先生 人气:0

一、说明

以下库用于设计模式。

本节内容

66. Boost.Flyweight

67. Boost.Signals2

68. Boost.MetaStateMachine

二、库Boost.Flyweight

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"});
}

Example 66.1 

示例 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"});
}

Example 66.3 

示例 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);
}

加载全部内容

相关教程
猜你喜欢
用户评论