Какой твой любимый трюк?
Я программировал на С++ уже довольно давно, но время от времени я натыкаюсь на фрагмент кода, использующий 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.