Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Main features

Boost , The Boost C++ Libraries BoostBook Documentation Subset , Chapter 9. Boost.Container

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Семантика перемещения и вставка размещения - это две функции, привнесенные контейнерами C++11, которые могут оказать очень положительное влияние на ваши приложения C++. Повышаю. Контейнер реализует обе технологии как для компиляторов C++11, так и C++03.

Все контейнеры, предлагаемые Boost.Container, могут хранить только подвижные типы и фактические требования для value_type зависят от каждой операции с контейнером. Следуя требованиям C++11 даже для компиляторов C++03, многие операции теперь требуют подвижных или конструируемых по умолчанию типов вместо просто копируемых конструируемых типов.

Сами контейнеры также являются подвижными, с гарантией отсутствия броска, если операции с выделением или предикатом (если присутствуют) не являются броском. Это позволяет выполнять высокопроизводительные операции при передаче данных между векторами. Давайте посмотрим пример:

#include <boost/container/vector.hpp>
#include <boost/move/utility_core.hpp>
#include <cassert>
//Non-copyable class
class non_copyable
{
   BOOST_MOVABLE_BUT_NOT_COPYABLE(non_copyable)
   public:
   non_copyable(){}
   non_copyable(BOOST_RV_REF(non_copyable)) {}
   non_copyable& operator=(BOOST_RV_REF(non_copyable)) { return *this; }
};
int main ()
{
   using namespace boost::container;
   //Store non-copyable objects in a vector
   vector<non_copyable> v;
   non_copyable nc;
   v.push_back(boost::move(nc));
   assert(v.size() == 1);
   //Reserve no longer needs copy-constructible
   v.reserve(100);
   assert(v.capacity() >= 100);
   //This resize overload only needs movable and default constructible
   v.resize(200);
   assert(v.size() == 200);
   //Containers are also movable
   vector<non_copyable> v_other(boost::move(v));
   assert(v_other.size() == 200);
   assert(v.empty());
   return 0;
}

Все контейнеры, предлагаемые Boost.Container, реализуют вставку размещения, что означает, что объекты могут быть встроены непосредственно в контейнер из аргументов пользователя без создания какого-либо временного объекта. Для компиляторов без вариадных шаблонов поддержка размещения вставки эмулируется до конечного (10) числа аргументов.

Дорогие для перемещения типы являются идеальными кандидатами для размещения функций и в случае контейнеров узлов ( список , набор , ...) место позволяет хранить неподвижные и некопируемые типы в контейнерах! Давайте посмотрим пример:

#include <boost/container/list.hpp>
#include <cassert>
//Non-copyable and non-movable class
class non_copy_movable
{
   non_copy_movable(const non_copy_movable &);
   non_copy_movable& operator=(const non_copy_movable &);
   public:
   non_copy_movable(int = 0) {}
};
int main ()
{
   using namespace boost::container;
   //Store non-copyable and non-movable objects in a list
   list<non_copy_movable> l;
   non_copy_movable ncm;
   //A new element will be built calling non_copy_movable(int) contructor
   l.emplace(l.begin(), 0);
   assert(l.size() == 1);
   //A new element will be value initialized
   l.emplace(l.begin());
   assert(l.size() == 2);
   return 0;
}

Неполные типы позволяют стирать типы и рекурсивные типы данных, а программисты C и C++ годами используют его для построения сложных структур данных, таких как структуры деревьев, где узел может иметь произвольное количество детей.

Как насчет стандартных контейнеров? Контейнеры неполных типов уже давно обсуждаются, как объясняется в замечательной статье Мэтта Остерна (Стандартный библиотекарь: Контейнеры неполных типов):

Unlike most of my columns, this one is about something you can't do with the C++ Standard library: put incomplete types in one of the standard containers. This column explains why you might want to do this, why the standardization committee banned it even though they knew it was useful, and what you might be able to do to get around the restriction.

In 1997, shortly before the C++ Standard was completed, the standardization committee received a query: Is it possible to create standard containers with incomplete types? It took a while for the committee to understand the question. What would such a thing even mean, and why on earth would you ever want to do it? The committee eventually worked it out and came up with an answer to the question. (Just so you don't have to skip ahead to the end, the answer is "no.") But the question is much more interesting than the answer: it points to a useful, and insufficiently discussed, programming technique. The standard library doesn't directly support that technique, but the two can be made to coexist.

In a future revision of C++, it might make sense to relax the restriction on instantiating standard library templates with incomplete types. Clearly, the general prohibition should stay in place - instantiating templates with incomplete types is a delicate business, and there are too many classes in the standard library where it would make no sense. But perhaps it should be relaxed on a case-by-case basis, and vector looks like a good candidate for such special-case treatment: it's the one standard container class where there are good reasons to instantiate it with an incomplete type and where Standard Library implementors want to make it work. As of today, in fact, implementors would have to go out of their way to prohibit it!

Стандарт C++11 также осторожно относится к неполным типам и STL: 17.6.4.8 Другие функции (...) 2. последствия не определены в следующих случаях: (...) В частности, если неполный тип (3.9) используется в качестве аргумента шаблона при инстанцировании компонента шаблона, если специально не разрешено для этого компонента .

К счастью, все контейнеры Boost.Container, за исключением static_vector и basic_string, предназначены для поддержки неполных типов. static_vector является специальным, поскольку он статически выделяет память для value_type и для этого требуются полные типы и basic_string реализует оптимизацию малых струн, которая также требует полных типов.

Boost.Container containers supporting incomplete types also support instantiating iterators to those incomplete elements.

Для определения рекурсивных контейнеров можно использовать большинство контейнеров Boost.Container:

#include <boost/container/vector.hpp>
#include <boost/container/stable_vector.hpp>
#include <boost/container/deque.hpp>
#include <boost/container/list.hpp>
#include <boost/container/map.hpp>
#include <boost/container/string.hpp>
using namespace boost::container;
struct data
{
   int               i_;
   //A vector holding still undefined class 'data'
   vector<data>      v_;
   vector<data>::iterator vi_;
   //A stable_vector holding still undefined class 'data'
   stable_vector<data> sv_;
   stable_vector<data>::iterator svi_;
   //A stable_vector holding still undefined class 'data'
   deque<data> d_;
   deque<data>::iterator di_;
   //A list holding still undefined 'data'
   list<data>        l_;
   list<data>::iterator li_;
   //A map holding still undefined 'data'
   map<data, data>   m_;
   map<data, data>::iterator   mi_;
   friend bool operator <(const data &l, const data &r)
   { return l.i_ < r.i_; }
};
struct tree_node
{
   string name;
   string value;
   //children nodes of this node
   list<tree_node>            children_;
   list<tree_node>::iterator  selected_child_;
};
int main()
{
   //a container holding a recursive data type
   stable_vector<data> sv;
   sv.resize(100);
   //Let's build a tree based in
   //a recursive data type
   tree_node root;
   root.name  = "root";
   root.value = "root_value";
   root.children_.resize(7);
   root.selected_child_ = root.children_.begin();
   return 0;
}

Контейнеры неполных типов полезны для разрушения зависимостей файла заголовка и улучшения типов компиляции. С Бустом. Контейнер, вы можете написать файл заголовка, определяющий класс с контейнерами неполных типов в качестве членов данных, если вы тщательно поместите все детали реализации, которые требуют знания размера value_type в файл реализации:

В этом файле заголовка мы определяем класс (MyClassHolder), который содержит вектор неполного типа (MyClass), который объявлен только вперед.

#include <boost/container/vector.hpp>
//MyClassHolder.h
//We don't need to include "MyClass.h"
//to store vector<MyClass>
class MyClass;
class MyClassHolder
{
   public:
   void AddNewObject(const MyClass &o);
   const MyClass & GetLastObject() const;
   private:
   ::boost::container::vector<MyClass> vector_;
};

Затем мы можем определить MyClass в собственном файле заголовка.

//MyClass.h
class MyClass
{
   private:
   int value_;
   public:
   MyClass(int val = 0) : value_(val){}
   friend bool operator==(const MyClass &l, const MyClass &r)
   {  return l.value_ == r.value_;  }
   //...
};

And include it only in the implementation file of MyClassHolder

//MyClassHolder.cpp
#include "MyClassHolder.h"
//In the implementation MyClass must be a complete
//type so we include the appropriate header
#include "MyClass.h"
void MyClassHolder::AddNewObject(const MyClass &o)
{  vector_.push_back(o);  }
const MyClass & MyClassHolder::GetLastObject() const
{  return vector_.back();  }

Наконец, мы можем просто собрать, связать и запустить!

//Main.cpp
#include "MyClassHolder.h"
#include "MyClass.h"
#include <cassert>
int main()
{
   MyClass mc(7);
   MyClassHolder myclassholder;
   myclassholder.AddNewObject(mc);
   return myclassholder.GetLastObject() == mc ? 0 : 1;
}

В статье N2913, озаглавленной SCARY Iterator Assignment and Initialization, предложено требование о том, что типы итераторов стандартного контейнера не зависят от какого-либо аргумента типа, кроме типа контейнера value_type, difference_type, pointer и const_pointer. В частности, согласно предложению, типы итераторов стандартного контейнера не должны зависеть от типов контейнера key_compare, hasher, key_equal или allocator.

Этот документ продемонстрировал, что операции SCARY имеют решающее значение для эффективного внедрения общих шаблонов проектирования с использованием компонентов STL. Он показал, что реализации, поддерживающие операции SCARY, уменьшают раздувание объектного кода, устраняя избыточные специализации итераторов и шаблонов алгоритмов.

Boost.Container containers implement SCARY iterators so the iterator type of a container is only dependent on the allocator_traits<allocator_type>::pointer type (the pointer type of the value_type to be inserted in the container). Reference types and all other typedefs are deduced from the pointer type using the C++11 pointer_traits utility. This leads to lower code bloat in algorithms and classes templated on iterators.

  • Конструкторы по умолчанию не выделяют память, которая улучшает производительность и обычно подразумевает гарантию отсутствия броска (если конструктор по умолчанию предиката или распределителя не бросает).
  • Небольшая струнная оптимизация для basic_string, с внутренним буфером 11/23 байт (32/64 битовых систем) без увеличивая обычный размер строки (3 слова).
  • [multi]set/map контейнеры размером оптимизированы для встраивания цветового бита узлов красно-черного дерева в родительский указатель.
  • [multi]set/map контейнеры не используют рекурсивных функций, поэтому проблем с стеком можно избежать.

PrevUpHomeNext

Статья Main features раздела The Boost C++ Libraries BoostBook Documentation Subset Chapter 9. Boost.Container может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: Chapter 9. Boost.Container ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-07-05 03:22:15/0.0064640045166016/0