Какой твой любимый трюк?

Я программировал на С++ уже довольно давно, но время от времени я натыкаюсь на фрагмент кода, использующий STL, который занял бы у меня довольно много времени и намного больше кода для выполнения.

STL требует довольно много времени, чтобы привыкнуть, и ресурсов не так много с реальными примерами того, как их использовать. Поделитесь своей любимой функцией STL со мной!

Ответ 1

dos2unix.cpp

#include <fstream>
#include <iterator>
#include <algorithm>

bool is_cr(char c) { return c == '\r'; }

int main(int, char* a[])
{
    std::ifstream is("/dev/stdin");
    std::ofstream os("/dev/stdout");
    std::istreambuf_iterator<char> in(is), end;
    std::ostreambuf_iterator<char> out(os);
    remove_copy_if(in, end, out, is_cr);
}

Ответ 2

Удаление некоторых элементов из вектора в линейном времени с помощью erase-remove-idiom:

vec.erase(std::remove(vec.begin(), vec.end(), is_odd), vec.end());

(Ручная петля через вектор и стирание на основе каждого элемента будет квадратичным временем.)

Ответ 3

Я помню тот, который мне очень понравился, когда я наткнулся на него (~ 10 лет назад) в comp.lang.c++.moderated:

int main(int argc, char* argv[])
{
  std::vector arguments(argv+1, argv+argc);
  // whatever
}

Сегодня я больше не использую это. Зачем вкладывать материал в вектор, который затем обрабатывается итераторами, когда у вас уже есть итераторы? Это теперь не касается STL как набора контейнеров и алгоритмов, но, тем не менее, идея, которую она принесла нам, для склеивания последовательностей и алгоритмов с помощью итераторов:

template<typename It>
int process_arguments(It begin, It end)
{
  // whatever we need to do with those arguments... 
}

int main(int argc, char* argv[])
{
  return process_arguments(argv+1, argv+argc);
}

(Да, я часто пишу небольшие утилиты консоли.)

Ответ 4

Использование вектора для буфера. Вместо:

int size_needed = GetData(NULL, 0);
char * buffer = new char[size_needed];
GetData(buffer, size_needed);
...
delete [] buffer;

Использование вектора:

int size_needed = GetData(NULL, 0);
std::vector<char> buffer(size_needed);
GetData(&buffer[0], size_needed);

Ответ 5

shared_ptr внутри shared_ptr.

Я иногда использую стандартный деструктор std:: shared_ptr для реализации простого пулаемого метода factory. Dunno, если это считается "трюком".

class Factory
{
    std::queue<std::shared_ptr<Type>> pool_; // Possibly tbb::concurrent_bounded_queue. Could also be contained as a shared_ptr to allow objects to outlive the factory.
public:
    std::shared_ptr<Type> create()
    {
        std::vector<Type> ptr;
        if(pool.empty())
            ptr = std::make_shared<Type>();
        else
        {
            ptr = std::move(pool_.front());
            pool_.pop();
        }

         return std::shared_ptr<Type>(ptr.get(), [=](Type*){pool_.push(ptr)};); // Put back into pool once destructed
     }
 }

Ответ 6

Мне больше всего нравится использование STL для кодирования функционального стиля. Например, подсчет элементов меньше 2:

n = std::count_if(v.begin(), v.end(), std::bind2nd(std::less<int>(), 2));

Ответ 7

Не особенно полезно, но мне нравится faking std::iota (где С++ 0x недоступен) с вызовом std::partial_sum:

    std::vector<int> v(5, 1); // 1, 1, 1, 1, 1
    partial_sum(v.begin(), v.end(), v.begin()); // 1, 2, 3, 4, 5

Что касается того, что я действительно использовал в производственном коде: тестирование, если два файла идентичны:

    if(equal(std::istreambuf_iterator<char>(file1),
             std::istreambuf_iterator<char>(),
             std::istreambuf_iterator<char>(file2)))
    { // files are equal, do whatever

В общем, я думаю, что partial_sum и inner_product заслуживают гораздо большей любви, чем они видят. С достаточно умными функторами они могут делать большие вещи.

Ответ 8

Мой любимый трюк STL позволяет избежать использования

  • CRT
  • raw указатели (С++ 0x).

Выразительность кода STL против эквивалента грубой силы удивительна.

Ответ 9

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