Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






  • Улучшения контейнеров






    Что же случилось со стандартными контейнерами, после появления новых языковых возможностей и десяти лет дополнительного опыта? Прежде всего, у нас появилось несколько новых контейнеров: array (контейнер фиксированного размера), forward_list (односвязный список) и неупорядоченные контейнеры (хеш-таблицы). Потом, контейнеры начали использовать новые языковые возможности, такие как списки инициализаторов, rvalue ссылки, шаблоны с переменным числом аргументов и constexpr. Давайте в качестве примера рассмотрим std:: vector.

    • Списки инициализации. Наиболее видимым улучшением является возможность конструирования с помощью списка инициализации, что позволяет контейнеру принимать список инициализации в качестве аргумента конструктора:

    vector< string> vs = { " Hello", ", ", " World! ", " \n" };

    for (auto s: vs) cout < < s;

    • Операторы перемещения. Контейнеры теперь содержат конструктор и оператор перемещения (в дополнение к существующим операциям копирования). Наиболее важным следствием из этого, является возможность эффективного возвращения из функций контейнеров:

    vector< int> make_random(int n)

    {

    vector< int> ref(n);

    // некоторый генератор случайных чисел

    for(auto& x: ref) x = rand_int(0, 255);

    Return ref;

    }

    vector< int> v = make_random(10000);

    for (auto x: make_random(1000000)) cout < < x < < '\n';

    Смысл здесь заключается в том, что вектор не копируется. Перепишите этот код с выделением вектора в куче и вы столкнетесь с проблемами управления памятью. Перепишите этот код так, чтобы вектор передавался в качестве аргумента в функцию make_random и вы получите значительно менее понятный код (в котором, к тому же, легче допустить ошибку).

    • Улучшенные операции добавления элементов. Моей любимой операцией контейнера является push_back(), которая позволяет элегантно увеличивать размер контейнеру:

    vector< pair< string, int> > vp;

    String s;

    Int i;

    while(cin> > s> > i) vp.push_back({s, i});

     

    В этом коде будет создан объект pair< string, int>, по значениям s и i, который затем будет перемещен в vp. Обратите внимание, он будет не «скопирован», а «перемещен». Существует перегруженная версия метода push_back, которая принимает в качестве аргумента rvalue ссылку, что позволяет использовать конструктор перемещения класса string. Также обратите внимание на использование унифицированного синтаксиса инициализации, что приводит к более короткому коду.

    • Устанавливающие (emplace) операции. Метод push_back() использует конструктор перемещения, который значительно более эффективен по сравнению со стандартными операциями копирования, но мы можем пойти еще дальше. Зачем вообще что-то копировать/перемещать? Почему бы не выделить в векторе нужный объем памяти и просто не создать нужное значение прямо в этой памяти? Такие операции называются “emplace” (т.е. «создающие на месте»). Давайте в качестве примера рассмотрим emplace_back():

    vector< pair< string, int> > vp;






    © 2023 :: MyLektsii.ru :: Мои Лекции
    Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
    Копирование текстов разрешено только с указанием индексируемой ссылки на источник.