Календарь на Май 2024 года: calendar2008.ru/2024/may/
Навигация
Главная »  Новости 

Ещё более современный C++


Источник: habrahabrru
Не так давно Герб Саттер открыл на своём сайте новую страничку - Elements of Modern C++ Style, где он описывает преимущества нового стандарта и то, как они повлияют на код.

 Стандарт C++11 вносит множество новых фич. Далее мы рассмотрим те из них, благодаря которым C++11 можно считать новым языком по сравнению с C++98, т.е.:
Они меняют стиль Вашего кода, привносят новые идиомы. Они повлияют на архитектуру С++ библиотек. Например: умные указатели получат большее распространение (и как аргументы функций, и как их возвращаемые значения), как и функции, возвращающие большие объекты по значению.
Они будут использоваться столь часто и интенсивно, что Вы, вероятно, будете встречать их в каждом втором примере кода. Например: вряд ли какой-нибудь пример из пяти или более строчек кода обойдётся без упоминания ключевого слова auto.

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

auto

 Используйте ключевое слово auto везде, где это возможно.
 Во-первых, не стоит повторять имя типа, о котором и мы, и компилятор уже знаем:
// C++98
map::iterator i = m.begin();
 
// C++11
auto i = begin(m);

 Во-вторых, так гораздо удобнее в случае, если тип имеет неизвестное или большое и неказистое имя, которое Вы даже произнести не в состоянии.
// C++98
binder2nd< greater > x = bind2nd( greater(), 42 );
 
// C++11
auto x = [](int i) { return i > 42; };

 Отметим, что использование auto не меняет смысла Вашего кода. Он по-прежнему статически типизирован, и каждое выражение по-прежнему обладает чётким и ясным типом. Просто язык больше не заставляет Вас повторяться, заново указывая тип.

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

Умные указатели: delete не нужен

 Всегда используйте стандартные умные указатели и невладеющие сырые указатели. Никогда не используйте владеющие сырые указатели и delete (кроме крайних случаев, вроде реализации низкоуровневой структуры).

 В общем случае указатель - это shared_ptr, выражающий общее владение.

// C++98
widget* pw = new widget();
:::
delete pw;
 
// C++11
auto pw = make_shared();

 Для разрыва циклических связей и выражения опциональности (например, реализации кеша объектов) используйте weak_ptr.
// C++11
class gadget;
 
class widget {
private:
    shared_ptr g;
};
 
class gadget {
private:
    weak_ptr w;
};

 В случае, если у указателя должен быть единственный владелец, используйте unique_ptr, предназначенный специально для этого случая. Любое выражение вида "new T" должно немедленно инициализировать другой объект, владеющий им, обычно unique_ptr.
// C++11 Pimpl Idiom
class widget {
    :::
private:
    class impl;
    unique_ptr pimpl;
};
 
// в .cpp файле
class impl {
    :::
};
 
widget::widget()
    : pimpl( new impl() )
{
}

 Если Вам нужно работать с объектом, который может пережить Вас, используйте сырой указатель.
// C++11
class node {
 vector< unique_ptr > children;
 node* parent;
public:
 :::
};

nullptr

 Всегда используйте для нулевого значения nullptr и никогда 0 или макрос NULL, поскольку они неоднозначны и могут быть как числом, так и указателем.
// C++98
int* p = 0;
 
// C++11
int* p = nullptr;

for и range

 С новым for'ом, умеющим работать с range, перебирать элементы контейнеров стало ещё проще и удобнее.
// C++98
for( vector::iterator i = v.begin(); i != v.end(); ++i ) {
    total += *i;
}
 
// C++11
for( auto d : v ) {
    total += d;
}

begin и end

 Всегда используйте begin и end как нечлены, потому что такой подход легко расширяем и позволяет работать со всеми типами контейнеров, а не только теми, которые следуют стилю STL и предоставляют методы .begin() и .end().

 Если Вы используйте не-STL коллекцию, которую можно проитерировать, но не реализующую методы .begin() и .end(), Вы можете самостоятельно перегрузить begin и end для неё так, чтобы итерировать эту коллекцию так же, как и контейнеры STL. Такая перегрузка, например, уже реализована для массивов в стиле C.
vector v;
int a[100];
 
// C++98
sort( v.begin(), v.end() );
sort( &a[0], &a[0] + sizeof(a)/sizeof(a[0]) );
 
// C++11
sort( begin(v), end(v) );
sort( begin(a), end(a) );

Лямбда функции

 Благодаря лямбдам Ваш код станет элегантнее и быстрее. С их появлением использовать существующие алгоритмы STL стало проще раз в 100. Новые библиотеки всё чаще полагаются на поддержку лямбда-функций (PPL), а некоторые и вовсе требуют их наличия (C++ AMP).

 Небольшой пример: найти первый элемент в v, который больше x и меньше y.
// C++98: пишем обычный цикл (использовать std::find_if сложно и непрактично)
vector::iterator i = v.begin(); // i нам ещё пригодится
for( ; i != v.end(); ++i ) {
    if( *i > x && *i < y ) break;
}
 
// C++11: используем std::find_if
auto i = find_if( begin(v), end(v), [=](int i) { return i > x && i < y; } );

 Обязательно ознакомьтесь с лямбдами. Они уже широко распространены во многих популярных языках. Для начала можно послушать мой доклад Lambdas, Lambdas Everywhere на PDC 2010.

Move / &&

 Семантика переноса сильно изменит дизайн наших API. Гораздо чаще станет использоваться возвращение по значению.
// C++98: как избежать копирования
vector* make_big_vector(); // вариант 1: возвращаем указатель: копирования нет, но не забудьте про delete
:::
vector* result = make_big_vector();
void make_big_vector( vector& out ); // вариант 2: выдача по ссылке: копирования нет, но вызывающему нужен именованный объект
:::
vector result;
make_big_vector( result );
 
// C++11: перенос
vector make_big_vector();
:::
vector result = make_big_vector();

 Если Вы можете сделать что-то более эффективное, чем простое копирование, используйте перемещение.

И ещё

 В современном C++ ещё много хороших вещей. Очень много. И в ближайшем будущем я напишу о них подробнее.

 Но на текущий момент, всё вышенаписанное - это must-know. Эти фичи лежат в основе современного C++, определяя его стиль. И совсем скоро Вы сможете встретить их практически в каждом кусочке свеженаписанного C++ кода. Именно они делают современный C++ чистым, безопасным и быстрым - таким, которым индустрия будет полагаться долгие годы.



 

 Перспективы карьерного роста для выпускников общественных колледжей с двухгодичным периодом обучения.
 Графика в Pascal.
 Персональная продажа услуг. Общие сведения.
 ABBYY поддержала команду из России на XXIV Международной олимпиаде по информатике (IOI).
 Business Objects завершает приобретение Armstrong Laing Limited.


Главная »  Новости 

© 2024 Team.Furia.Ru.
Частичное копирование материалов разрешено.