Показаны сообщения с ярлыком STL. Показать все сообщения
Показаны сообщения с ярлыком STL. Показать все сообщения

27 декабря 2010 г.

Нововведения в C++0x, которые не могут не радовать (меня)

Просмотрел повнимательнее список новшеств в будущем стандарте C++0x и обнаружил, что многие грабли, которые приходилось раньше реализовывать самостоятельно или городить воркэраунды, теперь будут поддерживаться конструкциями языка или добавлены в стандартную библиотеку. Это не может не радовать, потому что это сильно облегчает жизнь.

  1. Первым пунктом у меня идут потоки и объекты синхронизации (§30 [thread]): thread, mutex, lock, condition_variable, future, ... Наконец-то! Надеюсь, теперь можно будет выкинуть весь самописный код, который реализовывал классы с подобной функциональностью для использования на различных платформах. Конечно, было бы неплохо расширить список поддерживаемых Стандартом объектов синхронизации, но и существующий список вполне хорош.
  2. static_assert — проверка условий на этапе компиляции, которой так не хватало в предыдущих версиях Стандарта. Очень полезна для проверки размеров типов данных и кратности этих типов каким-то заданным значениям. (§7 [dcl.dcl])
  3. Списки инициализации и универсальная инициализация — новая синтаксическая конструкция (§8.5.4 [dcl.init.list]), которая позволяет инициализировать массивы, структуры данных и контейнеры следующим образом:
    double ad[] = { 1, 2.0 };
    S2 s22 { 1.0, 2, 3 };
    std::map<std::string, int> anim =
      { {"bear",4}, {"cassowary",2}, {"tiger",7} };

  4. shared_ptr — умные указатели (§20.9.11 [util.smartptr]). Объект, хранимый умным указателем, уничтожается только после того, как счетчик ссылок на объект будет равен нулю.
  5. Лямбда-выражения (§5.1.2 [expr.prim.lambda]). К самим по себе лямбда-выражениям я отношусь достаточно спокойно. Даже, пожалуй, скептически, потому что мне кажется, что фанатичное использование лямбда-выражений приведёт к хаосу (особенно выражений, которые изменяют состояние классов). Но у лямбда-выражений есть свойство, которого мне раньше не хватало — их можно передавать в классы и алгоритмы стандартной библиотеки (и в пользовательские шаблоны) в качестве предикатов. Раньше надо было городить кучу кода, определяя дополнительные функции и классы, причем передавать в шаблон локальный класс запрещено. А с новым стандартом можно сделать так:
    std::sort(x, x + N,
              [](float a, float b)
              { return std::abs(a) < std::abs(b); });

  6. Автоматический тип данных auto — тип объявляемой переменной определяется самостоятельно из типа инициализатора. Особенно удобно использовать при работе с итераторами контейнеров и другими типами, от которых зависит шаблон, чтобы не париться с горой typedef'ов. (§7.1.6.4 [dcl.spec.auto])
  7. Возможность вызова конструкторов класса из других конструкторов этого же класса (§12.6.2 [class.base.init]). Очень сильно облегчает написание конструкторов классов, помогает избежать дублирования кода инициализации.
  8. Цикл for по коллекциям (§6.5.4 [stmt.ranged]). Не очень актуально, учитывая появление auto и лямбда-выражений, но объём кода уменьшает.
    int array[5] = { 1, 2, 3, 4, 5 };
    for (int& x : array)
      x *= 2;

  9. Из маленьких приятных мелочей можно упомянуть поддержку генераторов случайных чисел (§26.5 [rand]), атомарных операций (§29 [atomics]), регулярных выражений (§28 [re]) и новых алгоритмов. Например, алгоритм iota (§27.6.5 [numeric.iota]), который заполняет заданный интервал инкрементирующимися значениями, начиная с заданного (подобный функционал я реализовывал с помощью алгоритма generate и самописного класса UniqueNumberGenerator).

9 декабря 2010 г.

STL: есть ли жизнь без исключений

Известно, что при компиляции кода можно отключить обработку исключений компилятором (например, опцией -fno-exceptions в GCC, или /EHs- в Visual Studio). Однако, отключение обработки исключений вовсе не означает, что программа не будет генерировать исключения. Это всего лишь означает, что компилятор не будет создавать код для обработки исключений и уничтожения автоматических объектов. А исключения будут продолжать генерироваться — операторами new при нехватке памяти, методом at() класса std::vector при выходе за пределы массива, просто операторами throw расставленными программистом по своему коду и т. д. Различие лишь в том, что так как в программе не будет вообще никакого кода, перехватывающего исключения, то любое сгенерированное в программе исключение приведет к вызову terminate().

Классы стандартной библиотеки сообщают об ошибках только с помощью исключений и никак иначе. Проблема использования STL в том, что когда мы отключаем поддержку исключений в проекте, то лишаемся механизма обработки ошибок. И если проблему с оператором new можно решить его заменой на new (nothrow), то исключение, генерируемое в аллокаторе при вызове vector::resize(), вроде как ничем не заменишь.

9 декабря 2008 г.

Освобождение памяти в std::vector

Я почему-то раньше был уверен, что выделенную память в std::vector можно освободить присваиванием:

typedef vector<int> int_vector;

int_vector v;
v.resize(10);
...
v = int_vector();

Оказалось, ошибался. Так не освобождает. По крайней мере, стандарт не обязывает.

Следовательно, остался только один способ освободить память — с помощью vector::swap:

int_vector().swap(v);


(способ описан в "Эффективном использовании STL" Скотта Мейерса)

12 сентября 2008 г.

Exceptions и Visual C++

Недавно понадобилось собрать STL-проект на Visual C++ 2008 без использования исключений.

Почитал мануал по компилятору, долго игрался с настройками проекта и ключами /EHsc... Что-то никак не получается отключить исключения.

Наконец, залез в код STL и обнаружил там некий волшебный макрос _HAS_EXCEPTIONS. Добавление в опции компиляции ключа -D_HAS_EXCEPTIONS=0 привело к нужному результату — исключения в STL отключились.

Припоминаю, что лет шесть назад пытался решить эту же задачу для Visual C++ 6.0. И решалась она абсолютно таким же способом, через _HAS_EXCEPTIONS. Вот я и думаю, то ли Microsoft что-то перемудрил с Visual C++, то ли я его "готовить" не умею?..

С праздником вас, дорогие коллеги! С днем программиста! :)

Updated: Если нужно линковаться с msvcrt.lib или msvcrtd.lib (опции компилятора /MD или /MDd), то нужно определить еще один макрос:
#define _STATIC_CPPLIB

Updated: Вот интересная статья в тему http://ccollomb.free.fr/blog/?p=34