C++

Программирование на Си-плюс-плюс: ТОП-10 трюков

Программирование на Си-плюс-плюс нельзя назвать привычным для современных разработчиков, но трюки, собранные в этой статье, значительно облегчат вам жизнь.

Си-плюс-плюс

Препроцессор

Макрос на определение размера массива:

template  
char (&ArraySizeHelper(T (&array)[N]))[N];
#define arraysize(array) (sizeof(ArraySizeHelper(array)))

Это лучше, чем обычный sizeof(array)/sizeof(array[0]), потому что вызывает краш при компиляции, если переданный массив является просто указателем или нулевым указателем, тогда как более простые макросы беззвучно возвращают бесполезное значение. Подробный пример см. в статье PVS-Studio vs Chromium.

Предопределенные макросы:

#define expect(expr) if(!expr) cerr << "Assertion " << #expr \
" failed at " << __FILE__ << ":" << __LINE__ << endl;
 
#define stringify(x) #x
#define tostring(x) stringify(x)
#define MAGIC_CONSTANT 314159
 
cout << "Value of MAGIC_CONSTANT=" << tostring(MAGIC_CONSTANT);

Макрос tostring – это общий трюк, конвертирующий значение переменной в строку. Ядро Linux использует множество подобных макросов.

Использование итераторов для быстрого сброса содержимого контейнера:

#define dbg(v) copy(v.begin(), v.end(), ostream_iterator<typeof(*v.begin())>(cout, " "))

Шаблон Voodoo

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

Например:

template
struct Choose {
  enum {value = (n * Choose<n-1, r-1>::value) / r};
};
 
template
struct Choose<n, 0> {
  enum {value = 1};
};
 
int main() {
    cout << Choose<8, 3>::value;
    int x[Choose<25, 3>::value];
}

Больше интересного по ссылке.

Менеджмент памяти и RAII

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

Подробнее.

Программирование на Си-плюс-плюс и URI в коде

Вы можете поместить URI в свой код на C++, и компилятор не выдаст ошибку.

#include 
int main() {
using namespace std;
http://www.google.com
int x = 5;
cout << x;
}

Любой идентификатор, за которым следует двоеточие, становится меткой goto в Си-плюс-плюс. Все, что следует за двойным слешем, воспринимается как комментарий. Именно поэтому в приведенном выше коде http – это метка, а //google.com/ – комментарий. Но компилятор может выдать предупреждение, так как заданная метка не используется.

Упрощаем дебаг

Определите оператор  << для структур STL, чтобы упростить добавление отладочных выходов в ваш код. Это лучше, чем стандартные функции вывода. Также определите соответствующий макрос. Пример для C++:

#include 
#include 
#include 


#ifdef NDEBUG
#define DEBUG(var)
#else
#define DEBUG(var) { std::cout << #var << ": " << (var) << std::endl; }
#endif
template
std::ostream& operator<< (std::ostream& out, const std::map<T1,T2> &M) {
    out << "{ ";
    for (auto item:M) out << item.first << "->" << item.second << ", ";
    out << "}";

Ключевое слово auto

Программирование на Си-плюс-плюс предполагает использование auto для итерации по карте, вектору, множеству, etc. Это ключевое слово указывает, что тип объявляемой переменной будет автоматически определен на основе типа инициализируемого выражения.

Стандартный вариант:

vector vs;
vs.push_back(4),vs.push_back(7),vs.push_back(9),vs.push_back(10);
for (vector::iterator it = vs.begin(); it != vs.end(); ++it)
    cout << *it << ' ';cout<<'\n';

Используем:

vector vs;
vs.push_back(4),vs.push_back(7),vs.push_back(9),vs.push_back(10);
for (auto it: vs)
    cout << it << ' ';cout<<endl;

  vector vs;
vs.push_back(4),vs.push_back(7),vs.push_back(9),vs.push_back(10);
for (auto& it: vs) it*=3;
for (auto it: vs)
    cout << it << ' ';cout<<endl;

Объявление переменной:

template
auto mult(A x, B y) -> decltype(x * y){
    return x * y;
}
int main(){
auto a = 3 * 2; //the return type is the type of operator (x*y) 
cout<<a<<endl;
    return 0;
}

Парные трюки

pair<int, int> p;
//Это
p = make_pair(1, 2);
//тождественно этому
p = {1, 2};
 
//Так что
pair<int, pair<char, long long> > p;
//теперь проще
p = {1, {'a', 2ll}};

Супер подключение

Просто используйте:

#include <bits/stdc++.h>

Эта библиотека включает в себя множество библиотек, которые нам нужны. Например, algorithm, iostream, vector и многие другие. Теперь вам не придется мучиться с запоминанием большого количества обязательных подключений.

Выводы

Можно долго распинаться на тему ненависти к C++, вытесняемому современными и актуальными языками, но поддержку существующих приложений никто не отменял. Приведенные в статье советы заметно ускорят процесс разработки и сохранят массу нервных клеток.

Дополнительная литература

Также рекомендуем Вам посмотреть:

Что такое мультиметоды в C++?
Подборка книг по C++ для любого уровня

МЕРОПРИЯТИЯ

Комментарии

ВАКАНСИИ

Добавить вакансию
C++ Developer
Новосибирск, от 120000 RUB до 180000 RUB
Senior Golang
Москва, от 3000 USD до 6000 USD
Product Manager
от 180000 RUB
QA инженер
от 105000 RUB до 135000 RUB

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ