Dyzzet|
C++
Data Science Алгоритмы Темы · Блог · YouTube
12 марта
Полиморфная кухня — 6. Умные указатели

В C++11 появились три вида умных (интеллектуальных) указателей: std::unique_ptr, std::shared_ptr и std::weak_ptr. Они избавляют от заботы освобождать память и другие ресурсы (если с ними правильно обращаться).

struct Base
{
    virtual void print() const noexcept
    {
        std::cout << "Base (const)" << std::endl;
    }
 
    virtual void print() noexcept
    {
        std::cout << "Base" << std::endl;
    }
 
    virtual ~Base() = default;
};

Читать далее →
Какие специальные функции неявно объявляет компилятор?


Из выступления Говарда Хиннанта

У классов в C++03 есть специальные члены-функции: пользовательские конструкторы (custom constructors), конструктор по умолчанию (default constructor), деструктор (destructor), конструктор копирующего присваивания (copy constructor), оператор копирующего присваивания (copy assignment operator). C++11 добавляет перемещающий конструктор (move constructor) и оператор перемещающего присваивания (move assignment operator) и спецификаторы = default и = delete.

Правила, по которым компилятор неявно объявляет и удаляет такие функции, очень сложные. Есть разные версии таблиц с подсказками. Но они показывают только особенности каждой специальной функции в отдельности.


// User declares:
// Compiler implicitly declares:
25 августа 2022
Зачем нужны owner_before и owner_less?

Конструирование std::shared_ptr

Умный указатель std::shared_ptr имеет очень хитрую вещь — конструктор псевдонима (aliasing constructor).

template <class U>
shared_ptr(const shared_ptr<U>& x, element_type* ptr) noexcept; // C++11
 
template <class U>
shared_ptr(shared_ptr<U>&& x, element_type* ptr) noexcept;      // C++20

Указатель x — владеемый указатель (owned pointer). Ниже подробно рассмотрим его роль.

Указатель ptr — это хранимый указатель (stored pointer), он хранится, но std::shared_ptr им не владеет и не управляет его временем жизни (сюда нужно передать «сырой» указатель).

Читать далее →
20 августа 2022
Как ограничить значения шаблонного параметра. От C++03 к C++11, 14 и 20

Представим, что есть класс, например, произвольного числа с плавающей запятой: с помощью шаблона пользователь может задать любые размеры экспоненты и мантиссы (size_t E, size_t M).

template <size_t E, size_t M>
class CustomFloat
{
    // ...
};

Как ограничить пользователя и задать: \(E\geqslant 5\) и \(M\geqslant 10\)? То есть значения \(E=8,\) \(M=23\) подходят:

CustomFloat<8, 23> f{};

А, например, значения \(E=4,\) \(M=10\) должны приводить к ошибке компиляции.

C++11

Если первый параметр шаблона true, то используется специализация с полем того же типа, что и второй параметр (см. ниже реализацию); my_enable_if_t<...> заменяется на тип, отличный от void. Если первый параметр шаблона false, используется неспециализированный шаблон пустой структуры, а второй параметр считается типом void; my_enable_if_t<...> заменяется на void, что не может быть скомпилировано.

Стандарт C++11 для таких целей ввёл шаблонную структуру std::enable_if.

template <size_t E, size_t M, std::enable_if<(E >= 5 && M >= 10), size_t>::type = 0>
class CustomFloat
{
    // ...
};

Читать далее →
14 августа 2022
std::accumulate, std::reduce и std::transform_reduce

Дана строка, содержащая цифры и некоторые латинские буквы. Нужно найти сумму всех цифр. Рассмотрим несколько решений.

unsigned sumOnlyDigits(const std::string& data)
{
    unsigned sum{};
    for (auto c : data)
    {
        if (isNumber(c))
        {
            sum += c - '0';
        }
    }
    return sum;
}

Код вполне прозрачный, он перебирает символы и находит сумму всех цифр с учётом того, что код '0' — 48, код '1' — 49, код '2' — 50 и т. д. То есть выражение c - '0' даёт числа в диапазоне 0...9 вместо 48...57.

std::accumulate

В STL есть функция std::accumulate из заголовочного файла <numeric>.

unsigned sumOnlyDigits(const std::string& str) noexcept
{
    return std::accumulate(str.cbegin(), str.cend(), 0u,
        [](unsigned partialSum, auto symbol) noexcept {
            return std::isdigit(symbol)
                ? (partialSum + static_cast<unsigned>(symbol - '0')) : partialSum;
        });
}

Читать далее →
14 июня 2022
Указатели и ссылки в языке C++. А также Java и C♯

В языке C++ практически с самого начала его существования есть две реализации ссылочного типа: это указатели (pointers) и ссылки (references). Указатели достались от языка C. Ссылки не заменили указатели во всём, а умные/интеллектуальные указатели (smart pointers) не всегда стоит использовать вместо «сырых» (raw pointers). В C++11 появился новый тип — rvalue-ссылки — который преследует совсем иные цели.

Ссылки появились в C++ ещё в тот момент, когда он миновал этап C with Classes, для перегрузки операторов:

Страуструп Б. «Дизайн и эволюция C++», оригинал 1994 года

«Дуг Макилрой вспоминает, что однажды я объяснял ему некоторые проблемы, касавшиеся схемы перегрузки операторов. Он употребил слово „ссылка“, после чего я, пробормотав „спасибо“, выбежал из его кабинета, чтобы на следующий день появиться с практически готовым решением, которое и вошло в язык. Просто Дуг тогда напомнил мне об Algol68».

В первом приближении разница между указателями и ссылками такова (для сравнения — ссылки в языках Java и C♯).

 
Указатели в C
Указатели в C++
Ссылки в C++
Ссылки в языках Java и C♯
Обязательно инициализировать
–
–
+
–
Можно переназначить
+ (если не const)
+ (если не const)
–
+
Значение по умолчанию
Мусорное
Мусорное
–
null
Невалидное значение
NULL
NULL/nullptr (C++11)
–
null
Коллекции
+
+
–
+
Арифметика
+
+
–
–
Косвенность
+
+
–
–

Читать далее →
11 июня 2022
Анализируем курс «Яндекса» по языку C++

C++ Russia 2018: Илья Шишков. Как научить языку C++: опыт создания курсов на Coursera (Youtube)

Teaching by making people uncomfortable. Kate Gregory’s Blog

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

Сегодня посмотрим выступление Ильи Шишкова (старший разработчик отдела безопасного поиска компании «Яндекс») на конференции C++ Russia 2018. Проанализируем вопрос в целом и это выступление в частности с точки зрения андрагогики (дисциплины, чей предмет — то, как нужно учить взрослых людей) и дидактики (теории обучения — такая дисциплина, которая занимается вопросами «Зачем, чему и как учить?»).

* * *

На курсе пять «поясов»: белый, жёлтый, красный, коричневый, чёрный. Заявленные цели: научить «самостоятельно решать практические задачи на языке C++», применять естественные идиомы и конструкции, самостоятельно находить ответы и изучать язык глубже; писать эффективный код без ущерба для качества.

Из выступления: «Чтобы они знали, какие есть источники информации, знали ключевые слова и могли, грубо говоря, нагуглить ответ на свой вопрос. Ой, меня просили не говорить слово „нагуглить“. Поискать в „Яндексе“».

Читать далее →
13 апреля 2022
Хаос в выражениях с инкрементом указателя

Навеяно «мемом»

Задача: записать значение x в нулевой элемент массива p и сместить указатель на следующий элемент.

Самый очевидный и чистый вариант:

p[0] = x;
++p;

Поскольку указатель на массив, используемый без квадратных скобок, означает адрес нулевого элемента, то есть p ≡ &p[0], его разыменование даёт сам нулевой элемент. Это означает, что *p ≡ p[0].

*p = x;
++p;

Эти две операции можно объединить. Но мы должны использовать пост-инкремент (указатель инкрементируется, оператор возвращает старый указатель).

*p++ = x;

Читать далее →
4
3 2 1
© MMXI—MMXXIII. RSS. Поддержать сайт
Светлая тема / тёмная тема