auto sp = std::make_shared<T>(123, "abc"); std::weak_ptr wp{sp}; std::shared_ptr<T> sh = wp.lock(); if (sh) std::cout << sh->str;
|
|
boost::scoped_ptr
(эквивалент std::unique_ptr
)
boost::shared_ptr
(аналог std::shared_ptr
)
boost::weak_ptr
(аналог std::weak_ptr
)
auto sp = std::make_shared<T>(123, "abc"); std::weak_ptr wp{sp}; std::shared_ptr<T> sh = wp.lock(); if (sh) std::cout << sh->str;
Адаптации:
scoped_array
— scoped_ptr
для массивов
intrusive_ptr
— счётчик ссылок находится в самом объекте
intrusive_ptr_add_ref
и intrusive_ptr_release
для своего типа
shared_array
— shared_ptr
для массивов
local_shared_ptr
— на каждый поток свой счётчик ссылок
std::SomeContainer<std::unique_ptr<T>>
boost::ptr_set<int> s; s.insert(new int{2}); s.insert(std::make_unique(1)); std::cout << *s.begin() << '\n';
Аналогично без использования умного контейнера:
std::set<std::unique_ptr<int>, boost::indirect_fun<std::less<int>>> v; v.insert(std::make_unique_ptr(2)); v.insert(std::make_unique_ptr(1)); std::cout << **v.begin() << '\n';
this
boost::lambda
BOOST_SCOPE_EXIT(&commit, this_) { if(!commit) this_->persons_.pop_back(); } BOOST_SCOPE_EXIT_END BOOST_SCOPE_EXIT_ALL(&, checkpoint, this) { if(checkpoint == p.evolution) this->persons_.pop_back(); };
simple_segregated_storage
— замена std::malloc
с разбиением памяти на сегменты
object_pool
— автоматически резервирует память под объекты. Основан на simple_segregated_storage
singleton_pool
— похож на simple_segregated_storage
, освобождает память всю целиком
pool_allocator
— аллокатор, может быть использован в стандартных контейнерах. Необходимо вручную освобождать память аллокатора
fast_pool_allocator
— аналогичем pool_allocator
, но память может быть не непрерывной. Используется в std::list
boost::object_pool<int> pool; int *i = pool.malloc(); *i = 1; pool.destroy(i); boost::simple_segregated_storage<std::size_t> storage; std::vector<char> v(42); storage.add_block(&v.front(), v.size(), 11); int *n = static_cast<int*>(storage.malloc()); *n = 45; storage.free(n); std::vector<int, boost::pool_allocator<int>> v{{7, 8, 99}}; ... boost::singleton_pool<boost::pool_allocator_tag, sizeof(int)>::purge_memory();
find_*
[1]
erase_*_copy
replace_*_copy
trim_left/right/_copy
, может использовать предикаты
is_any_of
, is_digit
, is_upper
, is_lower
, is_space
, …
starts_with
, ends_with
, contains
, lexicographical_compare
find_regex
join
std::vector v{{7, 8, 59}}; std::cout << boost::join(v, ",") << std::endl;
split
std::string s = "Boost C++ Libraries"; std::vector<std::string> v; boost::split(v, s, boost::is_space()); std::cout << v.size() << std::endl;
1 Символ *
— это first
, nth
, last
, all
, head
, tail
std::itoa
в обе стороны
>>
и <<
bad_lexical_cast
std::string s = boost::lexical_cast<std::string>(123); double d = boost::lexical_cast<double>(s); std::cout << s << " == " << d << std::endl;
std::printf
%
%1%
, %2%
и т.д.
boost::io::group
, которому также передаётся номер параметра, к которому манипулятор применяется
%|1$+|
std::printf
#include <iostream> #include <boost/format.hpp> int main() { std::cout << boost::format("%|1$#x| %2% %1%\n") % 123 % 456 << std::endl; }
0x7b 456 123
std::regex
regex_match
— одиночный матч
regex_search
— поиск соответствия с группировкой
regex_replace
— позволяет делать замены (для замен групп используются \\1
, \\2
и т.д.)
regex_token_iterator
— позволяет итерироваться по группам
cpp_regex_traits
и imbue
#include <iostream> #include <regex> int main() { std::string s = "Boost Libraries"; std::regex expr{R"((\w+)\s*(\w+))"}; if (std::smatch what; std::regex_search(s, what, expr)) { std::cout << what[0] << '\n'; std::cout << what[1] << "_" << what[2] << '\n'; } }
Boost Libraries
Boost_Libraries
sregex::compile
как в boost::regex
\w
→ _w
, \s
→ _s
и т.д.
[]
_
означает текущее найденное выражение
boost::spirit
[]
является лямбда выражением, аналогичным в boost::lambda
#include <iostream> #include <iterator> #include <string> #include <boost/xpressive/xpressive.hpp> #include <boost/xpressive/regex_actions.hpp> int main() { namespace xpr = boost::xpressive; std::string s{"Boost Libraries"}; auto r = xpr::sregex::compile(R"(\w+\s*\w+)"); xpr::sregex r2 = +xpr::_w >> xpr::_s >> +xpr::_w; std::cout << xpr::regex_match(s, r) << " == " << xpr::regex_match(s, r2) << std::endl; std::ostream_iterator<std::string> it{std::cout, "\n"}; xpr::sregex r3 = (+xpr::_w)[*xpr::ref(it) = xpr::_] >> xpr::_s >> +xpr::_w; std::cout << std::boolalpha << xpr::regex_match(s, r3) << std::endl; }
1 == 1
Boost
true
boost::char_separator
основной класс сепаратора, конструктор принимает
escaped_list_separator
: разделитель символ ,
, все символы возврата обрабатываются
offset_separator
задаёт конкретные интервалы сепаратора. Подходит для бинарного анализа файла
#include <iostream> #include <string> #include <boost/tokenizer.hpp> int main() { std::string_view s{"Boost C++ Libraries"}; boost::char_separator<char> sep{" ", "+", boost::keep_empty_tokens}; boost::tokenizer tok{s, sep}; for (const auto& t : tok) std::cout << t << '\n'; }
Boost
C
+
+
Libraries
x3
)
qi::parse
— применяет парсер/грамматику для итератора
qi::phrase_parse
— повторяет предыдущее + умеет игнорировать пробельные символы
boost::spirit::x3
member
, const_mem_fun
(mem_fun
), identity
, global_fun
, composite_key
modify
get
для получения конкретного интерфейса
Интерфейс | Совместимый тип |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
#include <iostream> #include <boost/multi_index_container.hpp> #include <boost/multi_index/sequenced_index.hpp> #include <boost/multi_index/ordered_index.hpp> #include <boost/multi_index/random_access_index.hpp> #include <boost/multi_index/member.hpp> int main() { struct animal { std::string name; int legs; }; boost::multi_index::multi_index_container< animal, boost::multi_index::indexed_by< boost::multi_index::sequenced<>, boost::multi_index::ordered_non_unique< boost::multi_index::member< animal, int, &animal::legs > >, boost::multi_index::random_access<> > > animals; animals.emplace_back("cat", 4); animals.emplace_back("shark", 0); animals.emplace_back("spider", 8); auto& legs_index = animals.get<1>(); auto it = legs_index.find(4); legs_index.modify(it, [](animal &a){ a.name = "dog"; }); for (const auto& x : animals) std::cout << x.name << " " << x.legs << "\n"; }
dog 4
shark 0
spider 8
boost::multi_index_container
left
и right
для получения интерфейса std::set
boost::bimaps::set_of
используется по умолчанию
boost::bimaps::multiset_of
используется для неуникальных значений
boost::bimaps::list_of
, boost::bimaps::vector_of
, boost::bimaps::unconstrained_set_of
, …
boost::bimaps::_key
и boost::bimaps::_data
#include <iostream> #include <string> #include <boost/bimap.hpp> #include <boost/bimap/support/lambda.hpp> int main() { boost::bimap<std::string, boost::bimaps::unconstrained_set_of<int>> animals; animals.insert({"cat", 4}); animals.insert({"shark", 0}); animals.insert({"spider", 8}); auto it = animals.left.find("cat"); animals.left.modify_key(it, boost::bimaps::_key = "dog"); for (const auto& [key, val] : animals) std::cout << key << ":" << val << "\n"; }
dog:4
shark:0
spider:8
int a[42]
std::array
operator==
и hash_value
std::unordered_set/multiset
и std::unordered_map/multimap
std::vector
is_linearized
— можно ли буфер представить только одним массивом
array_one
, array_two
— голова и хвост буфера
linearize
— перераспределение элементов
#include <iostream> #include <boost/circular_buffer.hpp> int main() { boost::circular_buffer<int> cb{3}; cb.push_back(0); cb.push_back(1); cb.push_back(2); cb.push_back(3); std::cout << std::boolalpha << cb.is_linearized() << '\n'; auto ar1 = cb.array_one(); auto ar2 = cb.array_two(); std::cout << ar1.second << ";" << ar2.second << std::endl; }
false
2;1
std::priority_queue
priority_queue
позволяет не только вставлять элементы, но и итерироваться по ним
binomial_heap
позволяет:
fibonacci_heap
предоставляет вставку за O(1)
#include <algorithm> #include <iostream> #include <iterator> #include <boost/heap/binomial_heap.hpp> int main() { boost::heap::binomial_heap<int> bh; bh.push(2); bh.push(3); bh.push(1); boost::heap::binomial_heap<int> bh2; bh2.push(4); bh.merge(bh2); std::copy(bh.ordered_begin(), bh.ordered_end(), std::ostream_iterator<int>(std::cout, "\n")); }
4
3
2
1
list
и set
с точки зрения попадания в кеш
list/set_base_hook
list/set_member_hook
link_mode
#include <iostream> #include <boost/intrusive/list.hpp> int main() { struct animal : public boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>> { std::string name; int legs; animal(std::string name, int legs) : name(std::move(name)), legs(legs) {} }; animal a1{"cat", 4}; animal a2{"ostrich", 2}; animal *a3 = new animal{"spider", 8}; boost::intrusive::list<animal, boost::intrusive::constant_time_size<false>> animals; animals.push_back(a1); animals.push_back(a2); animals.push_back(*a3); delete a3; for (const animal &a : animals) std::cout << a.name << '\n'; }
cat
ostrich
boost::extents[N][M]
для задания размера матрицы NxM
operator[]
, либо использовать boost::indices
origin
предоставляет доступ к сырому указателю
boost::multi_array_ref
и boost::const_multi_array_ref
являются обёртками над C-массивом
#include <algorithm> #include <array> #include <iostream> #include <experimental/iterator> #include <boost/multi_array.hpp> int main() { boost::multi_array<double, 3> a{boost::extents[3][6][8]}; a[0][0][7] = 3.14; a(std::array{1, 1, 7}) = 2.718; using range = boost::multi_array_types::index_range; using index = range::index; auto view = a[boost::indices[range()][range() < index(5)][index(4) <= range().stride(2) <= index(7)]]; for (auto v1 : view) for (auto v2 : v1) for (auto& x : v2) x = 77; for (const auto& v1 : a) { for (const auto& v2 : v1) { std::copy(v2.begin(), v2.end(), std::experimental::make_ostream_joiner(std::cout, ", ")); std::cout << "\n"; } std::cout << "\n"; } }
0, 0, 0, 0, 77, 0, 77, 3.14
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 77, 0, 77, 2.718
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 77, 0, 77, 0
0, 0, 0, 0, 0, 0, 0, 0
stable_vector
позволяет изменять данные, при это итераторы всегда остаются валидными
flat_set/map
представляют "плоские" структуры, без деревьев
slist
== std::forward_list
static_vector
подобен std::array
, но ведёт себя как std::vector
small_vector
имеет преалоцированную память, подходит для массивов с малой длиной
io
для каждого из типов
path_type
позволяет использовать свой разделить в пути
put
— положить значение по ключу
put_child
— положить ptree
по ключу
add_child
— добавить ptree
к ключу (эмуляция массива)
get_value
— получить значение, тип определяется шаблонным параметром
get_optional
— получить значение или нет
get_child
— получить потомка ptree
get_child_optional
— получить потомка или нет
json_parser::write_json
и json_parser::read_json
дают возможность сериализовать ptree
ini_parser
и xml_parser
#include <iostream> #include <string> #include <boost/property_tree/ptree.hpp> int main() { namespace bpt = boost::property_tree; bpt::ptree pt; pt.put("drive.win.system", "20 files"); auto c = pt.get_optional<std::string>("drive"); std::cout << std::boolalpha << c.is_initialized() << '\n'; pt.put_child("drv.files", bpt::ptree{"50 files"}); pt.add_child("drv.files", bpt::ptree{"60 files"}); bpt::ptree d = pt.get_child("drv"); for (const auto& [key, val] : d) std::cout << val.get_value<std::string>() << '\n'; boost::optional<bpt::ptree&> e = pt.get_child_optional("ala"); std::cout << e.is_initialized() << std::endl; }
true
50 files
60 files
false
std::bitset
std::bitset
to_block_range
позволяет сделать сериализацию данных
#include <iostream> #include <vector> #include <string> #include <boost/dynamic_bitset.hpp> int main() { boost::dynamic_bitset<uint32_t> db(std::string("11010110101")); std::vector<uint32_t> v{{8, 779, 65564, 5321, 556}}; db.append(v.begin(), v.end()); db.push_back(true); db.append(4485); std::cout.setf(std::ios::boolalpha); std::cout << db.size() << '\n'; std::cout << db.count() << '\n'; std::cout << db.any() << '\n'; std::cout << db.none() << '\n'; std::cout << db[0].flip() << '\n'; std::cout << ~db[3] << '\n'; std::vector<uint32_t> out; boost::to_block_range(db, std::back_inserter(out)); for (auto x : out) std::cout << x << "\n"; }
204
33
true
false
false
true
18100
1595392
134275072
10897408
1138688
18372608
0
indeterminate
tribool_io.hpp
для вывода всех состояний
#include <iostream> #include <boost/logic/tribool.hpp> #include <boost/logic/tribool_io.hpp> int main() { using namespace boost::logic; std::cout.setf(std::ios::boolalpha); boost::logic::tribool b1 = true; std::cout << (b1 || indeterminate) << '\n'; std::cout << (b1 && indeterminate) << '\n'; boost::logic::tribool b2 = false; std::cout << (b2 || indeterminate) << '\n'; std::cout << (b2 && indeterminate) << '\n'; boost::logic::tribool b3 = boost::logic::indeterminate; std::cout << (b3 || b3) << '\n'; std::cout << (b3 && b3) << '\n'; }
true
indeterminate
indeterminate
false
indeterminate
indeterminate
std::pair
compressed_pair
использует меньше памяти
first()
и second()
#include <iostream> #include <utility> #include <boost/compressed_pair.hpp> int main() { struct empty {}; std::pair<int, empty> p; boost::compressed_pair<int, empty> cp; std::cout << sizeof(p) << " vs. " << sizeof(cp) << std::endl; }
8 vs. 4
cxx11
, cxx14
one_of_equal
, all_of_equal
, any_of_equal
, none_of_equal
copy
: copy_while
, copy_until
is_sorted
, is_increasing
, is_decreasing
clamp
, find_not
, find_backward
, gather
, hex
, is_palindrome
, is_partitioned_until
, apply_permutation
#include <iostream> #include <iterator> #include <string> #include <vector> #include <boost/algorithm/hex.hpp> #include <boost/algorithm/gather.hpp> int main() { namespace ba = boost::algorithm; std::cout << ba::unhex(std::string("432b2b")) << '\n'; ba::hex(std::vector<char>{'C', '+', '+'}, std::ostream_iterator<char>(std::cout, "")); std::cout << "\n"; std::vector v{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}; auto p = ba::gather(v.begin(), v.end(), v.begin() + 4, [](auto x) { return x % 2 == 0; }); for (auto it = p.first; it != p.second; ++it) std::cout << *it << " "; std::cout << "\n"; }
C++
432B2B
0 2 4 6 8
begin
и end
— это диапазоны
filter
— фильтрация по предикату
key
и values
— адапторы для map
indirect
нужен для разыменовывания указателей в массиве
tokenize
— разбиение строки на токены по регулярному выражению
iterator_range
— на базе его можно организовать свои диапазоны
irange
позволяет создавать целочисленный диапазон на лету
istream_range
превращает стрим в диапазон
#include <iostream> #include <string> #include <experimental/iterator> #include <boost/range/irange.hpp> #include <boost/range/algorithm/copy.hpp> #include <boost/range/istream_range.hpp> int main() { auto ir = boost::irange(0, 3); boost::copy(ir, std::experimental::make_ostream_joiner(std::cout, ", ")); std::cout << "\n"; auto sr = boost::istream_range<int>(std::cin); boost::copy(sr, std::ostream_iterator<int>{std::cout, "\n"}); }
$ ./example5-2 <<< "45 89 53"
0, 1, 2
45
89
53
adjacency_list
чаще всего используется
adjacency_matrix
применяется, когда количество рёбер примерно соответствует квадрату количества вершин
edge_list
представляется из себя адаптор
adjacency_list<OutEdgeList, VertexList, Directed, VertexProperties, EdgeProperties, GraphProperties, EdgeList>
vecS
, listS
, setS
, …
directedS
, undirectedS
boost::property<boost::edge_weight_t, int>
или boost::no_property
add_vertex
, add_edge
для добавления вершин и рёбер
out_edges
, in_edges
, adjacent_vertices
для выяснения выходящих/входящих рёбер и соседних вершин
![]() Рисунок 1. Пример направленного графа
|
![]() Рисунок 1. Пример хранения графа в
adjacency_list |
enum vertex { A, B, C, D, E, F }; std::vector<std::pair<vertex, vertex>> edges{{ {B, C}, {B, F}, {C, A}, {C, C}, {D, E}, {E, D}, {F, A} }}; std::array weights{{2, 1, 1, 1, 3, 4, 2}}; boost::adjacency_list<boost::vecS, boost::vecS, boos::undirectedS> g{6, edges.begin(), edges.end(), weights.begin()}; auto [first, last] = boost::edges(g); std::copy(first, last, std::ostream_iterator<typename decltype(g)::edge_descriptor>(std::cout, "\n"));
breadth_first_search
или обход в ширину (волновой обход)
depth_first_search
или обход в глубину
uniform_cost_search
обход по наиболее выгодным вершинам
distance_map
, weight_map
, color_map
, predecessor_map
, …
boost::array<int, 6> directions; boost::dijkstra_shortest_paths(g, B, boost::predecessor_map(directions.begin())); int p = A; while (p != B) { std::cout << p << '\n'; p = directions[p]; } std::cout << p << std::endl;
io_service
steady_timer
ip::tcp::socket
, ip::tcp::iostream
, ip::udp
serial_port
(USB, UART, …)
std::thread thread1{[&ioservice](){ ioservice.run(); }};
#include <iostream> #include <boost/asio.hpp> int main() { using namespace std::literals; boost::asio::io_service ioservice; boost::asio::steady_timer timer1{ioservice, 3s}; timer1.async_wait([](auto) { std::cout << "3 sec\n"; }); boost::asio::steady_timer timer2{ioservice, 4s}; timer2.async_wait([](auto) { std::cout << "4 sec\n"; }); ioservice.run(); }
3 sec
4 sec
io_service ioservice; ip::tcp::endpoint tcp_endpoint{ip::tcp::v4(), 2018}; ip::tcp::acceptor tcp_acceptor{ioservice, tcp_endpoint}; ip::tcp::socket tcp_socket{ioservice}; std::string data; tcp_acceptor.listen(); tcp_acceptor.async_accept(tcp_socket, [&data, &tcp_socket](const boost::system::error_code& ec) { if (!ec) { data = "tra-la-la"; async_write(tcp_socket, buffer(data), [](const boost::system::error_code& ec, size_t bytes) { if (!ec) tcp_socket.shutdown(tcp::socket::shutdown_send); }); } }); ioservice.run();
boost::asio::ip::tcp::iostream s("www.boost.org", "http"); s.expires_from_now(std::chrono::seconds(60)); s << "GET /LICENSE_1_0.txt HTTP/1.0\r\n" s << "Host: www.boost.org\r\n"; s << "Accept: */*\r\n"; s << "Connection: close\r\n\r\n" << std::flush; std::string header; while (std::getline(s, header) && header != "\r") std::cout << "HEAD: " << header << std::endl; std::cout << "BODY: " << s.rdbuf();
io_service ioservice; ip::tcp::endpoint tcp_endpoint{ip::tcp::v4(), 2018}; ip::tcp::acceptor tcp_acceptor{ioservice, tcp_endpoint}; std::list<ip::tcp::socket> tcp_sockets; auto do_write = [](tcp::socket &tcp_socket, yield_context yield) { std::string data = "u-la-la"; async_write(tcp_socket, buffer(data), yield); tcp_socket.shutdown(tcp::socket::shutdown_send); } auto do_accept = [&tcp_sockets, &ioservice, &tcp_acceptor, do_write](yield_context yield) { for (int i = 0; i < 2; ++i) { tcp_sockets.emplace_back(ioservice); tcp_acceptor.async_accept(tcp_sockets.back(), yield); spawn(ioservice, [](yield_context yield) { do_write(tcp_sockets.back(), yield); }); } } tcp_acceptor.listen(); spawn(ioservice, do_accept); ioservice.run();
shared_memory_object
создаёт/открывает разделяемую память по имени на чтение/запись
mapped_region
shared_memory_object::remove
remove_shared_memory_on_destroy
#include <iostream> #include <boost/interprocess/shared_memory_object.hpp> #include <boost/interprocess/mapped_region.hpp> int main() { namespace bi = boost::interprocess; bi::shared_memory_object shdmem{bi::open_or_create, "Boost", bi::read_write}; shdmem.truncate(1024); bi::mapped_region region{shdmem, bi::read_write}; int *i1 = static_cast<int*>(region.get_address()); *i1 = 99; bi::mapped_region region2{shdmem, bi::read_only}; int *i2 = static_cast<int*>(region2.get_address()); std::cout << *i2 << std::endl; }
99
shared_memory_object::remove("Boost"); managed_shared_memory managed_shm{open_or_create, "Boost", 1024}; int *i = managed_shm.construct<int>("Integer")[10](99); std::cout << *i << "\n"; std::pair<int*, std::size_t> p = managed_shm.find<int>("Integer"); if (p.first) std::cout << *p.first << ":" << p.second << "\n"; using char_allocator = boost::allocator<char, managed_shared_memory::segment_manager>; using string = boost::basic_string<char, std::char_traits<char>, char_allocator> string; string* s = managed_shm.find_or_construct<string>("String")("Hello!", managed_shm.get_segment_manager()); s->insert(5, ", world"); std::cout << *s << std::endl; managed_shm.destroy<int>("Integer");
boost/interprocess/sync/
named_mutex
interprocess_mutex
named_recursive_mutex
и interprocess_recursive_mutex
named_condition
interprocess_condition
managed_shared_memory managed_shm{open_or_create, "shm", 1024}; int *i = managed_shm.find_or_construct<int>("Integer")(0); interprocess_mutex *mtx = managed_shm.find_or_construct<interprocess_mutex>("mtx")(); named_condition named_cnd{open_or_create, "cnd"}; std::lock_guard lock{*mtx}; while (*i < 10) { if (*i % 2 == 0) { ++(*i); cnd->notify_all(); cnd->wait(lock); } else { std::cout << *i << std::endl; ++(*i); cnd->notify_all(); cnd->wait(lock); } } cnd->notify_all(); shared_memory_object::remove("shm");
read
и write
array_sink
, array_source
предоставляют в качестве устройств массивы
back_insert_device
file_sink
и file_source
для работы с файлами
mapped_file_source
и mapped_file_sink
для работы с файлами в памяти
file_descriptor_source
и file_descriptor_sink
для работы с нативными дескрипторами
stream
namespace bio = boost::iostreams; std::vector<char> v; bio::back_insert_device<std::vector<char>> sink{v}; bio::stream os{sink}; os << "Boost" << std::endl; bio::file_source f{"text.txt"}; if (f.is_open()) { bio::stream is{f}; std::cout << is.rdbuf() << std::endl; }
filtering_istream
и filtering_ostream
namespace bio = boost::iostreams; std::vector<char> v; bio::back_insert_device<std::vector<char>> snk{v}; bio::filtering_ostream os; os.push(bio::zlib_compressor{}); os.push(snk); os << "Boost" << std::flush; os.pop(); bio::array_source src{v.data(), v.size()}; bio::filtering_istream is; is.push(bio::zlib_decompressor{}); is.push(bio::counter{}); is.push(src); std::string s; is >> s; auto *c = os.component<counter>(0); std::cout << s << "\n" << "Stats: characters = " << c->characters() << " lines = " << c->lines() << std::endl;
boost::filesystem::path
позволяет описывать пути, является основным для работы типом
filesystem::path
boost::gregorian::date
для работы с календарём
boost::gregorian::day_clock
для получения текущей даты
universal_day()
и local_day()
date_from_iso_string()
служит для преобразования ISO-форматированной строки в объект date
date_duration
нужен для произведения вычислений с датой
date_period
нужен для поддержания диапазона времени
contains
позволяет узнавать принадлежность даты какому-то периоду
day_iterator
, week_iterator
, … — итератор, позволяет итерироваться по датам
#include <iostream> #include <boost/date_time/gregorian/gregorian.hpp> int main() { namespace bg = boost::gregorian; bg::date d{2018, 11, 19}; bg::months ms{1}; bg::date d2 = d + ms; bg::date d3 = d2 - ms; std::cout << d2 << " vs. " << d3 << std::endl; }
2018-Dec-19 vs. 2018-Nov-19
posix_time
даёт возможность манипулировать временем
time_duration
, time_period
local_time
#include <iostream> #include <boost/date_time/gregorian/gregorian.hpp> #include <boost/date_time/posix_time/posix_time.hpp> int main() { namespace bp = boost::posix_time; namespace bg = boost::gregorian; bp::ptime pt{bg::date{2014, 5, 12}, bp::time_duration{12, 0, 0}}; bp::time_iterator it{pt, bp::time_duration{6, 30, 0}}; std::cout << *++it << "\n" << *++it << std::endl; }
2014-May-12 18:30:00
2014-May-13 01:00:00
steady_clock
возвращает монотонное время
system_clock
возвращает текущее время, чувствительно к переводу часов
high_resolution_clock
предоставляет самый точный хронометраж в системе
process_real_cpu_clock
возвращает время с момента старта программы
process_user_cpu_clock
возвращает затраченное время в пользовательском пространстве
process_system_cpu_clock
возвращает затраченное время в режиме ядра
process_cpu_clock
возвращает кортеж из затраченных времён
thread_clock
работает как steady_clock
, но для потока
chrono_io.hpp
#include <iostream> #include <boost/chrono.hpp> int main() { namespace bc = boost::chrono; auto p = bc::process_real_cpu_clock::now(); std::cout << p << "\n" << bc::time_point_cast<bc::minutes>(p) << std::endl; }
17180161340000000 nanoseconds since process start-up
286336 minutes since process start-up
cpu_timer
для автоматической замеры времени
start()
позволяет перезапускать таймер, конструктор делает это автоматически
stop()
, resume()
для временной остановки таймера
fromat()
выводит всю информацию по пройденному времени
elapsed()
возвращает структуру с временными метриками
wall
, user
, system
— полное время, время в пространстве пользователя и ядра
auto_cpu_timer
в деструкторе делает std::cout << timer.format()
#include <iostream> #include <cmath> #include <boost/timer/timer.hpp> int main() { boost::timer::auto_cpu_timer timer; for (int i = 0; i < 1000000; ++i) std::pow(1.234, i); std::cout << "Done\n"; }
Done
0.017470s wall, 0.010000s user + 0.000000s system = 0.010000s CPU (57.2%)
val
для заместителя значения переменной, ref
— для ссылки (область захвата лямбда-выражения)
arg1
для заместителя аргумента лямбда-выражения (всегда возвращает свой первый аргумент)
boost::phoenix::function
нужен для декорации своего функтора
BOOST_PHOENIX_ADAPT_FUNCTION
используется для формирования отложенной лямбды из C-функции
boost::phoenix::bind
— альтернатива предыдущему
if_
для записи условных выражений
[ st1, st2, st3 ]
равносильно определению блока кода { st1; st2; st3; }
#include <iostream> #include <boost/phoenix/phoenix.hpp> int main() { using namespace boost::phoenix::placeholders; std::vector v{{1, 2, 3, 4, 5}}; std::for_each(v.begin(), v.end(), std::cout << arg1 << ","); }
1,2,3,4,5,
std::function
std::bind
std::bind
boost::ref
есть версия с константной ссылкой boost::cref
std::ref
и std::cref
boost::phoenix
и лямбда-выражений в C++11
#include <algorithm> #include <iostream> #include <vector> #include <boost/lambda/lambda.hpp> #include <boost/lambda/if.hpp> int main() { std::vector v{{1, 3, 2}}; std::for_each(v.begin(), v.end(), boost::lambda::if_then(boost::lambda::_1 > 1, std::cout << boost::lambda::_1 << "\n") ); }
3
2
std::thread
, кроме
boost::scoped_thread
interrupt()
, который позволяет остановить выполнение потока
boost::this_thread::disable_interruption
предотвращает создание точек прерывания
boost::thread::attributes
в конструкторе потока позволяет настраивать запуск потока
boost::thread_group
служит для одновременном запуске нескольких потоков
boost::thread_specific_ptr
для компиляторов, не поддерживающих thread_local
из C++11
future
, promise
, async
, packaged_task
были взяты в STL
#include <iostream> #include <memory> #include <mutex> #include <thread> #include <boost/thread/tss.hpp> int main(int argc, const char**) { std::mutex mutex; auto helper = [](auto& ptr) { if (!ptr.get()) { ptr.reset(new bool{true}); std::cout << "done" << '\n'; } }; auto worker = [&mutex, &helper, flag = argc > 1]() { static boost::thread_specific_ptr<bool> ptr1; static std::shared_ptr<bool> ptr2; std::lock_guard lock{mutex}; if (flag) helper(ptr2); else helper(ptr1); }; std::thread t[] = {std::thread{worker}, std::thread{worker}, std::thread{worker}}; for (auto& x : t) x.join(); }
done
done
done
done
memory_order_seq_cst
строгая последовательность (используется по умолчанию)
memory_order_relaxed
разрешает любые переупорядочивания команд
memory_order_release
разрешает выполнение команд в коде строго до этой команды в конвейере
memory_order_acquire
разрешает выполнение команд в коде строго после этой команды в конвейере
spsc_queue
— single producer, single consumer
capacity<num>
queue
— multiple producer, multiple consumer
stack
capacity
задаёт размер очереди
fixed_sized
устанавливает политику фиксированной по размеру очереди
allocator
позволяет использовать свой аллокатор
push
и pop
consume_one
и consume_all
consume_on
вернёт false
.
Поэтому нужны допольнительные механизмы детектирования окончания работы с очередью
#include <atomic> #include <future> #include <iostream> #include <thread> #include <boost/lockfree/queue.hpp> int main() { boost::lockfree::queue<int> q(100); std::atomic<int> sum = 0; auto produce = [&q]() { for (int i = 1; i <= 100; ++i) { q.push(i); std::this_thread::yield(); } }; std::function<int(decltype(sum)&)> consume = [&q](auto& x) { int count = 0; while (q.consume_one([&x](int i){ x += i; })) ++count; return count; }; std::thread t1{produce}; auto t2 = std::async(consume, std::ref(sum)); auto t3 = std::async(consume, std::ref(sum)); t1.join(); std::cout << "Thread2 count " << t2.get() << "\n" << "Thread3 count " << t3.get() << "\n" << "Sum " << sum << "\n"; q.consume_all([&sum](int i){ sum += i; }); std::cout << sum << std::endl; }
Thread2 count 46
Thread3 count 5
Sum 1326
5050
boost::mpi::environment
нужен для запуска MPI, есть только конструктор
boost::mpi::communicator
recv
, send
позволяют обмениваться сообщениями
irecv
, isend
аналогичны предыдущим, но неблокирующие
boost::mpi::request
wait_all
, wait_any
и wait_some
для блокирования
rank()
для определения своего идентификатора
boost::mpi::any_source
для принятия сообщения от любого процесса
gather
позволяет собрать данные со всех процессоров в одном месте
scatter
раздаёт данные процессам из вектора
broadcast
раздаёт одинаковые данные всем процессам
reduce
аналогично gather
, но аккумулирует данные через функцию, а не вектор
reduce_all
аналогично reduce
, но результат будет доступен всем процессам
split
и group
можно формировать своё подмножество процессов
#include <algorithm> #include <iostream> #include <string> #include <boost/mpi.hpp> int main(int argc, char* argv[]) { boost::mpi::environment env{argc, argv}; boost::mpi::communicator world; std::string s = "Hello, others!"; if (world.rank() == 0) s = "Hello, world!"; else if (world.rank() == 1) s = "Hello, moon!"; else if (world.rank() == 2) s = "Hello, sun!"; std::cout << "I am process " << world.rank() << " on " << world.size() << ", my value is [" << s << "]\n"; std::string result; boost::mpi::reduce(world, s, result, [](const auto&... xs) { return std::min(xs...); }, 0); if (world.rank() == 0) std::cout << "The alphabet lowest output is [" << result << "]\n"; }
mpirun ./example10-3
I am process 1 on 2, my value is [Hello, moon!]
I am process 0 on 2, my value is [Hello, world!]
The alphabet lowest output is [Hello, moon!]
is_integral
, is_arithmetic
, is_same
, …
true_type
, false_type
has_plus
, has_pre_increment
, add_rvalue_reference
, …
constexpr
boost::mpl
, но предоставляет работу со значениями
boost::fusion::vector
аналогичен boost::fusion::tuple
, который аналогичен простому tuple
fusion::map
ключами являются типы, значения могут принимать любой тип
using namespace boost::fusion; vector<int, std::string, bool, double> v{10, "Boost", true, 3.14}; auto v2 = push_back(v, 'X'); std::cout << at<boost::mpl::int_<4>>(v2) << std::endl;
BOOST_FUSION_ADAPT_STRUCT
auto m = make_map<uint8_t, uint16_t, uint32_t>("Boost", 10, 3.14); if (has_key<uint16_t>(m)) std::cout << at_key<uint16_t>(m) << std::endl;
yield
и await
pull_type
и push_type
tuple
#include <iostream> #include <string> #include <tuple> #include <boost/coroutine2/coroutine.hpp> int main() { namespace bc2 = boost::coroutines2; auto cooperative = [](bc2::coroutine<std::tuple<int, std::string>>::pull_type &source) { auto args = source.get(); std::cout << "first = " << std::get<0>(args) << " " << std::get<1>(args) << "\n"; source(); args = source.get(); std::cout << "second = " << std::get<0>(args) << " " << std::get<1>(args) << "\n"; }; bc2::coroutine<std::tuple<int, std::string>>::push_type sink{cooperative}; std::cout << "start: "; sink(std::make_tuple(0, "aaa")); std::cout << "next: "; sink(std::make_tuple(1, "bbb")); std::cout << "end\n"; }
start: first = 0 aaa
next: second = 1 bbb
end
BOOST_PARAMETER_FUNCTION
и BOOST_PARAMETER_NAME
делают всю работу
#include <iostream> #include <string> #include <boost/parameter.hpp> BOOST_PARAMETER_NAME(a) BOOST_PARAMETER_NAME(b) BOOST_PARAMETER_NAME(c) BOOST_PARAMETER_NAME(d) BOOST_PARAMETER_NAME(e) BOOST_PARAMETER_FUNCTION( (void), complicated, tag, (required (a, (int)) (b, (char))) (optional (c, (double), 3.14) (d, (std::string), "Boost") (e, *, true)) ) { std::cout.setf(std::ios::boolalpha); std::cout << a << '\n'; std::cout << b << '\n'; std::cout << c << '\n'; std::cout << d << '\n'; std::cout << e << '\n'; } int main() { complicated(_b = 'B', _a = 1, _d = "lala"); }
1
B
3.14
lala
true
dynamic_cast
boost::polymorphic_downcast
для кастования к наследнику из базового класса
boost::polymorphic_cast
для кастования между базовыми классами
#include <iostream> #include <boost/cast.hpp> struct base1 { virtual ~base1() = default; }; struct base2 { virtual ~base2() = default; }; struct derived : public base1, public base2 {}; void downcast(base1 *b1) { derived* d = boost::polymorphic_downcast<derived*>(b1); std::cout << d << "\n"; } void crosscast(base1 *b1) { base2* b2 = boost::polymorphic_cast<base2*>(b1); std::cout << b2 << "\n"; } int main() { derived* d = new derived; downcast(d); base1* b1 = new derived; crosscast(b1); }
0x2088eb0
0x2089ee8
error_code
, errc::make_error_code
, …
boost::system::error_category
error_code
для платформо специфичных ошибок, error_condition
для всех платформ
boost::system::system_error
используется для генерации исключения на базе error_code
#include <iostream> #include <system_error> int main() { try { throw std::system_error{std::make_error_code(std::errc::not_supported)}; } catch (const std::system_error& e) { std::error_code ec = e.code(); std::cerr << ec.value() << '\n'; std::cerr << ec.category().name() << std::endl; } }
95
generic
std::exception
BOOST_THROW_EXCEPTION
позволяет сохранять информацию о файле и строчке исключения
boost::error_info
std::nested_exception
boost::diagnostic_information
для получения всей информации об исключении
boost::get_error_info
вывод информации об исключении напрямую
1: #include <iostream> 2: #include <string> 3: #include <stdexcept> 4: 5: #include <boost/exception/all.hpp> 6: 7: int main() 8: { 9: using errmsg_info = boost::error_info<struct tag_errmsg, std::string>; 10: 11: try 12: { 13: try 14: { 15: BOOST_THROW_EXCEPTION(std::runtime_error{"123"}); 16: } 17: catch (const boost::exception& e) 18: { 19: e << errmsg_info{"writing lots of zeros failed"}; 20: throw; 21: } 22: } 23: catch (const boost::exception& e) 24: { 25: std::cerr << *boost::get_error_info<errmsg_info>(e); 26: std::cerr << boost::diagnostic_information(e); 27: } 28: }
writing lots of zeros failed/home/runner/work/master-programming/master-programming/lecture-9/example13-2.cpp(15): Throw in function int main()
Dynamic exception type: boost::wrapexcept<std::runtime_error>
std::exception::what: 123
[main::tag_errmsg*] = writing lots of zeros failed
accumulator_set
для создания аккумулятора по тэгу
std::complex
, std::valarray
, std::vector
и примитивными типами
count
, mean
, variance
, moment<N>
нужны для получения итогового значения
#include <iostream> #include <boost/accumulators/accumulators.hpp> #include <boost/accumulators/statistics.hpp> int main() { namespace ba = boost::accumulators; ba::accumulator_set<double, ba::features<ba::tag::mean, ba::tag::variance>, int> acc; acc(8, ba::weight=1); acc(9, ba::weight=1); acc(10, ba::weight=4); acc(11, ba::weight=1); acc(12, ba::weight=1); std::cout << ba::mean(acc) << ":" << ba::variance(acc) << std::endl; }
10:1.25
boost::numeric_cast
позволяет производить преобразование числа в разные типы
positive_overflow
, negative_overflow
, …
boost::numeric::converter
позволяет создавать конвертеры более детально
bounds
служит для определения границ числа, соответствует std::numeric_limits
#include <iostream> #include <boost/numeric/conversion/cast.hpp> int main() { try { int i = 0x10000; short s = boost::numeric_cast<short>(i); std::cout << s << std::endl; } catch (boost::numeric::bad_numeric_cast &e) { std::cout << e.what() << std::endl; } }
bad numeric conversion: positive overflow
cstdint
std::minmax
, std::minmax_element
random
main
boost::parameters
и boost::fusion
#include <boost/log/core.hpp> #include <boost/log/trivial.hpp> #include <boost/log/expressions.hpp> #include <boost/log/sinks/text_file_backend.hpp> #include <boost/log/utility/setup/file.hpp> #include <boost/log/utility/setup/common_attributes.hpp> #include <boost/dll/runtime_symbol_info.hpp> namespace bg = boost::log; void init() { auto exe_path = boost::dll::program_location(); bg::add_file_log ( bg::keywords::file_name=exe_path.parent_path() / "sample_%N.log", // <1> bg::keywords::rotation_size=10 * 1024 * 1024, // <2> bg::keywords::time_based_rotation=bg::sinks::file::rotation_at_time_point(0, 0, 0), // <3> bg::keywords::format="[%TimeStamp%]: %Message%" // <4> ); bg::core::get()->set_filter(bg::trivial::severity >= bg::trivial::info); bg::add_common_attributes(); // <5> } int main() { init(); BOOST_LOG_TRIVIAL(trace) << "A trace severity message"; BOOST_LOG_TRIVIAL(debug) << "A debug severity message"; BOOST_LOG_TRIVIAL(info) << "An informational severity message"; BOOST_LOG_TRIVIAL(warning) << "A warning severity message"; BOOST_LOG_TRIVIAL(error) << "An error severity message"; BOOST_LOG_TRIVIAL(fatal) << "A fatal severity message"; }
Паттерн имени лога
Условие размера лога при ротации
Возможна также ротация по времени, например, в полночь
Формат сообщений, которые будем видеть в логах
Включение общих атрибутов, например, %TimeStamp%
$ ./example15-1
$ cat ./sample_0.log
[2023-12-18 06:03:59.426792]: An informational severity message
[2023-12-18 06:03:59.426926]: A warning severity message
[2023-12-18 06:03:59.426937]: An error severity message
[2023-12-18 06:03:59.426943]: A fatal severity message
git remote prune origin
)
=
--
, команда пишется полностью, в BSD используется один дефис
--has-default positional options here
⇒ --has-default -- positional options here
variables_map
, стоит взглянуть на https://github.com/jarro2783/cxxopts
boost::program_options::error
parse_environment()
и environment_iterator
можно загружать опции через переменные окружения
#include <fstream> #include <iostream> #include <string> #include <boost/program_options.hpp> int main(int argc, char** argv) { namespace po = boost::program_options; po::options_description generalOptions{"General"}; generalOptions.add_options() ("help,h", "Help screen") ("config", po::value<std::string>()->default_value("/etc/config.cfg"), "Config file") ("age", po::value<int>(), "Age"); po::variables_map vm; po::store(po::parse_command_line(argc, argv, generalOptions), vm); if (vm.count("config")) { std::ifstream ifs{vm["config"].as<std::string>()}; if (ifs) po::store(po::parse_config_file(ifs, generalOptions), vm); } po::notify(vm); if (vm.count("help")) std::cout << generalOptions << std::endl; else if (vm.count("age")) std::cout << "Your age is: " << vm["age"].as<int>() << std::endl; }
$ ./example15-2 -h
General:
-h [ --help ] Help screen
--config arg (=/etc/config.cfg) Config file
--age arg Age
$ ./example15-2 --age 21
Your age is: 21
$ ./example15-2 --config <(echo age = 22)
Your age is: 22
boost::archive::text_oarchive
и boost::archive::text_iarchive
— простейшие сериализаторы, обёртки над стримами
boost::serialization::access
void serialize(Archive& ar, const unsigned int version)
Archive
— это сериализатор
ar
нужно с помощью оператора &
void serialize(Archive& ar, MyAwesomeObject& a, const unsigned int version)
BOOST_CLASS_VERSION(MyAwesomeObject, 42)
boost::serialization::base_object<BaseClass>(*this);
BOOST_CLASS_EXPORT
boost::serialization::make_array(a.data(), a.size())
make_binary_object
используется для сырых данных, например, бинарные данные изображения
#include <iostream> #include <sstream> #include <boost/serialization/base_object.hpp> #include <boost/archive/text_oarchive.hpp> #include <boost/archive/text_iarchive.hpp> class animal { public: animal(int legs = 0) : legs_{legs} {} int legs() const { return legs_; } private: friend class boost::serialization::access; template <typename Archive> void serialize(Archive &ar, const unsigned int /*version*/) { ar & legs_; } int legs_; }; class bird : public animal { public: bird(bool can_fly = true) : animal{2}, can_fly_{can_fly} {} bool can_fly() const { return can_fly_; } private: friend class boost::serialization::access; template <typename Archive> void serialize(Archive &ar, const unsigned int /*version*/) { ar & boost::serialization::base_object<animal>(*this); ar & can_fly_; } bool can_fly_; }; int main() { std::stringstream ss; auto serialize = [](auto& os, const bird& obj) { boost::archive::text_oarchive oa{os}; oa << obj; }; auto deserialize = [](auto& is) { boost::archive::text_iarchive ia{is}; bird obj; ia >> obj; return obj; }; bird penguin{false}; serialize(ss, penguin); bird b = deserialize(ss); std::cout << b.legs() << " " << std::boolalpha << b.can_fly() << std::endl; }
2 false
nil_generator
производит нулевой UUID 00000000-0000-0000-0000-000000000000
random_generator
полностью случайный UUID
string_generator
для генерации UUID из строки по стандарту
name_gen
для получения UUID строки
size
размер, всегда равен 16 байтам
is_nil
является ли UUID нулевым
variant
и version
позволяют понять, какой стандарт использовался при генерации UUID
to_string
или boost::lexical_cast<std::string>
позволяет получить UUID в виде строки
#include <iostream> #include <boost/uuid/uuid.hpp> #include <boost/uuid/uuid_generators.hpp> #include <boost/uuid/uuid_io.hpp> int main() { boost::uuids::string_generator string_gen; boost::uuids::uuid id = string_gen("CF77C981-F61B-7817-10FF-D916FCC3EAA4"); std::cout << id.variant() << ":" << id.version() << " = " << id << std::endl; }
0:-1 = cf77c981-f61b-7817-10ff-d916fcc3eaa4
set_factory
использовать std::set
для хранения объектов, а не хешированный массив
no_locking
не использовать примитивы синхронизации а-ля мьютексы
no_tracking
не отслеживать время жизни объект
#include <iostream> #include <string> #include <vector> #include <boost/flyweight.hpp> struct person { struct country {}; int id; boost::flyweight<std::string> city; boost::flyweight<std::string, boost::flyweights::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"}); std::cout << "100th: " << persons[100].city << " " << &persons[100].city.get() << "\n" << "200th: " << persons[200].city << " " << &persons[200].city.get() << "\n"; }
100th: Berlin 0xe4f2d0
200th: Berlin 0xe4f2d0
std::function
connect
позволяет подсоединять свои функции к определённому сигналу (слоты)
disconnect
обратное действие
num_slots
позволяет узнать, сколько обработчиков подписано на этот сигнал
operator*
boost::signals2::shared_connection_block
используется для временного прекращения работы слота
#include <iostream> #include <boost/signals2.hpp> int main() { boost::signals2::signal<void()> s; auto hello = [] { std::cout << "Hello, world!" << std::endl; }; auto disconnect = [&s, hello] { s.disconnect(hello); }; s.connect(hello); s.connect(disconnect); s(); s(); }
Hello, world!
current_state
для получения текущего состояния
process_event
для переключения состояния
fsm_
для получения доступа к внутренним атрибутам
boost::msm::front::state<>
служит для полного определения состояний
boost::msm::front::state_machine
позволяет определять машину состояний
#include <iostream> #include <type_traits> #include <boost/msm/front/euml/euml.hpp> #include <boost/msm/front/euml/state_grammar.hpp> #include <boost/msm/back/state_machine.hpp> using namespace boost::msm::front::euml; BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int, switched_on) BOOST_MSM_EUML_STATE((), Off) BOOST_MSM_EUML_STATE((), On) BOOST_MSM_EUML_EVENT(press) BOOST_MSM_EUML_ACTION(WriteMessage) { template<class Evt, class Fsm, class SourceState, class TargetState> void operator()(const Evt&, Fsm&, const SourceState&, const TargetState&) { if constexpr (std::is_same_v<SourceState, decltype(Off)>) std::cout << "Switched on\n"; else std::cout << "Switched off\n"; } }; BOOST_MSM_EUML_TRANSITION_TABLE(( Off + press [fsm_(switched_on) < Int_<2>()] / (++fsm_(switched_on), WriteMessage()) == On, On + press / WriteMessage() == Off ), light_transition_table) BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( light_transition_table, init_ << Off, no_action, no_action, attributes_ << switched_on ), light_state_machine) int main() { boost::msm::back::state_machine<light_state_machine> light; std::cout << "Current state: " << *(light.current_state()) << "\n"; light.process_event(press); std::cout << "Current state: " << *(light.current_state()) << "\n"; light.process_event(press); std::cout << "Current state: " << *(light.current_state()) << "\n"; light.process_event(press); std::cout << "Current state: " << *(light.current_state()) << "\n"; light.process_event(press); std::cout << "Current state: " << *(light.current_state()) << "\n"; light.process_event(press); std::cout << "Current state: " << *(light.current_state()) << "\n"; }
Current state: 0
Switched on
Current state: 1
Switched off
Current state: 0
Switched on
Current state: 1
Switched off
Current state: 0
Current state: 0
boost::checked_delete()
и boost::checked_array_delete()
делают аналогичную работу за delete
и delete[]
BOOST_CURRENT_FUNCTION
выдаёт имя текущей функции
__func__
boost::prior()
и boost::next()
аналогичные std::prev
и std::next
boost::noncopyable
автоматически убирает все порождающие операторы копирования
boost::addressof()
позволяет получить адрес объекта, даже если operator&
перегружен
std::addressof
BOOST_BINARY(1001 0001)
позволяет создавать константы в двоичном формате
0b
boost::string_ref
аналогично std::string_view
list_of
, map_list_of
и т.д.
std::initializer_list
push_back
, push_front
, insert
и push
,
std::vector<std::pair<std::string, int>> v = boost::assign::list_of<std::pair<std::string, int>>("a", 1)("b", 2)("c", 3); std::vector<int> v2; boost::assign::push_back(v2)(1)(2)(3); using namespace boost::assign; vector<int> values; values += 1,2,3,4,5,6,7,8,9;
boost::less_than_comparable
достаточно определить лишь operator<
class MyInt : boost::operators<MyInt> { bool operator<(const MyInt& x) const; bool operator==(const MyInt& x) const; MyInt& operator+=(const MyInt& x); MyInt& operator-=(const MyInt& x); MyInt& operator*=(const MyInt& x); MyInt& operator/=(const MyInt& x); MyInt& operator%=(const MyInt& x); MyInt& operator|=(const MyInt& x); MyInt& operator&=(const MyInt& x); MyInt& operator^=(const MyInt& x); MyInt& operator++(); MyInt& operator--(); };