Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

C трюки и советы из Boost на всякий день

Anna | 24.06.2014 | нет комментариев

 


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

Что вас ждёт под катом:

  • чураемся вызовов макросов взамен функций, на примере max/min.
  • Вызываем оптимальную функцию, на примере std::swap и её специализации в различных пространствах имен.
  • Ускоряем вставку в std::vector.
  • Деструкторы в C 11.

чураемся вызовов макросов взамен функций, на примере max/min.

Те кто много работают с Visual Studio наверно сталкивались с тем, что min/max — это макросы. Из-за чего фактически всякие функции min/max в всяких классах и пространствах имен трактуются препроцессором как макроподстановки. В следствие этого следующие примеры кода не компилируются:

int max_int = std::numeric_limits<int>::max();
my_class_variable.max();

Есть разные методы избежать вызовов макросов взамен функций, но самый переносимый и короткий — это легко заключить каждый вызов функции в круглые скобки (помимо самих круглых скобок):

int max_int = (std::numeric_limits<int>::max)();
(my_class_variable.max)();

Сейчас препроцессор не воспримет max как вызов макроса и код скомпилируется правильно. Данный трюк срабатывает со всеми макросами, не только с min/max, и Зачастую применяется в Boost.

Вызываем оптимальную функцию, на примере std::swap и её специализации в различных пространствах имен.

Представьте себе обстановку: вам необходимо обменять значения 2-х переменных особенно результативным образом. Традиционно для этого применяют функции swap. Но вот напасть, мы пишем обобщенный код тот, что должен трудиться с пользовательскими типами:

template <class T>
void my_function(T& value1, T& value1) {
    // ...
    std::swap(value1, value2); // не оптимальное решение!
    // ...
}

Неоптимальность решения заключается в том, что пользовательские типы могут иметь свою функцию swap, которая работает гораздо результативнее стандартной версии:

namespace some_namespace {
    class my_vector;
    void swap(my_vector& value1, my_vector& value2);
} // some_namespace

Дюже простым решением задачи будет поправить код дальнейшим образом:

template <class T>
void my_function(T& value1, T& value1) {
    using std::swap;
    // ...
    swap(value1, value2);
    // ...
}

Сейчас компилятор в первую очередь будет пытаться обнаружить функцию swap из пространств имен параметров value1 и value2. Другими словами, если value1 и value2 являются экземплярами класса some_namespace::my_vector, то компилятор в первую очередь будет пытаться применять swap из some_namespace. Если в пространствах имен параметров value1 и value2 не будет функции swap, компилятор будет применять std::swap.

Отчего происходит именно так? Потому что компилятор должен исполнить Argument Dependent Lookup (он же Koenig Lookup) раньше чем пытаться сделать вызов функции из using. Именно этим трюком пользуется boost::swap, а boost::numeric_cast использует подобный подход для функций floor, ceil и др.

Ускоряем вставку в std::vector.

Начнем с довольно банального совета: если вы знаете число элементов, которые будут вставлены в вектор, то перед вставкой нужно вызвать reserve(число элементов для вставки):

std::vector<int> numbers;
numbers.reserve(1000);
for (size_t i = 0; i < 1000;   i)
    numbers.push.back(i);
// ...

Данный совет имеется во множестве учебников по программированию, но отчего-то о нем Зачастую забывают. Из недавних примеров где об этом позабыли — код Unity (графической оболочки Ubuntu).

Сейчас менее банальный совет. В C 11 было решено, что std::vector и ряд других контейнеров могут применять move-конструкторы и move-assignment операторы для элементов только если move-конструкторы и move-assignment операторы этих элементов не кидают исключений (ну либо если элементы не могут копироваться).

Другими словами, в C 11 для достижения наилучшей продуктивности стоит помечать конструкторы и операторы, не кидающие исключения, как noexcept.

Помимо контейнеров из стандартной библиотеки, многие классы из Boost Эмоциональны к noexcept, скажем boost::variant и boost::circular_buffer.

Деструкторы в C 11.

Ещё до эталона С 11 кидать исключения в деструкторах считалось дюже плохим тоном. В C 11 это ведет к гибели приложения.

В С 11 все деструкторы объектов механически помечаются как noexcept. Это ведет к тому, что если у вас есть класс, тот, что кидает исключение в деструкторе, то в C 11 в этом случае будет вызван std::terminate() и всё приложение завершится без вызова деструкторов для сделанных объектов.

Безусловно дозволено это обойти, очевидно сказать компилятору что деструктор кидает исключение… Но не отменнее ли сделать все по отличному?

Взамен результатов

В книге имеется много увлекательного по С и Boost, рассказывать дозволено длинно. Что бы вы хотели услышать в первую очередь:

В дальнейшей статье вы бы хотели узнать огромнее о…

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Проголосовало 36 человек. Воздержалось 10 человек.

 

Источник: programmingmaster.ru

 

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB