Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.52/597: Рейтинг темы: голосов - 597, средняя оценка - 4.52
 Аватар для Kastaneda
5232 / 3206 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2

С++ идиомы

31.07.2016, 19:20. Показов 166267. Ответов 34
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Перевод статей 1 и 2. Будет постепенно обновляться. Желающие внести вклад могут писать в ЛС.

 Комментарий модератора 
Тема открыта, просьба добавлять только посты с переводом, обсуждение здесь


Переведенные идиомы:
self-assignment in an assignment operator
Scope Guard
Shrink-to-fit
Checked delete
Pointer To Implementation
Получение адреса(ака взятие адреса aka Address-of)
nullptr
Iterator Pair
Coercion by Member Template
14
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
31.07.2016, 19:20
Ответы с готовыми решениями:

С++ идиомы - обсуждение
Тема создана для вопросов и обсуждений С++ идиом

Как и какие идиомы и паттерны можно (и лучше) применять?
Здравствуйте. Писал я проги для себя ну и так по мелочи, для абы кого, да и проги абы как, не задумываясь о том как какие идиомы (паттерны)...

Идиомы программирования
диома программирования — это некоторое часто применяемое действие в прораммировании. Это самый низкоуровневый шаблон проектировввния. ...

34
фрилансер
 Аватар для Алексей1153
6504 / 5748 / 1134
Регистрация: 11.10.2019
Сообщений: 15,392
14.03.2021, 21:21
Студворк — интернет-сервис помощи студентам
JeyCi,

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main(int argc, const char *argv[])
{
    int a=2;
    {
       vector<unique_ptr<AbstractShape>>  v;
       v.emplace_back(new Square(a));
       v.emplace_back(new Circle(a));
       v.emplace_back(new Rectangle(a, 4));
            
        for(const auto& el : v)
        {
            cout << el->area() << '\n'; 
        }
    }
    return 0;
}
1
19506 / 10109 / 2464
Регистрация: 30.01.2014
Сообщений: 17,834
16.03.2021, 14:56
Цитата Сообщение от JeyCi Посмотреть сообщение
часто CRTP описывается только с template'ом и наследниками
Потому что именно это в его названии и заложено.

Вообще я убежден, что CRTP должен быть элементом дизайна, а не оптимизации.
Нет никакого смысла вводить его только ради оптимизации. Должны быть более фундаментальные причины.
1
19506 / 10109 / 2464
Регистрация: 30.01.2014
Сообщений: 17,834
16.03.2021, 15:44
JeyCi, я вам тут прикрепил pdf-ку со статьей из журнала C++ Report от 95 года по CRTP. Думаю полезно будет ознакомиться для полного понимания.
Вложения
Тип файла: pdf The-C-Report (CRTP).pdf (854.5 Кб, 27 просмотров)
2
Любитель чаепитий
 Аватар для GbaLog-
3745 / 1801 / 566
Регистрация: 24.08.2014
Сообщений: 6,020
Записей в блоге: 1
16.03.2021, 16:36
Цитата Сообщение от Алексей1153 Посмотреть сообщение
да, я слегка ошибся - у тебя запутанная архитектура ) Утечки не будет

Не по теме:

Кликните здесь для просмотра всего текста
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
anon@DESKTOP:/mnt/d/Projects/tmp$ valgrind --leak-check=full ./a.out
==75== Memcheck, a memory error detector
==75== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==75== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==75== Command: ./a.out
==75==
==75== error calling PR_SET_PTRACER, vgdb might block
4
12.56
8
==75==
==75== HEAP SUMMARY:
==75==     in use at exit: 56 bytes in 3 blocks
==75==   total heap usage: 11 allocs, 8 frees, 73,384 bytes allocated
==75==
==75== 16 bytes in 1 blocks are definitely lost in loss record 1 of 3
==75==    at 0x4C3217F: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==75==    by 0x109189: main (crtp_leak.cpp:63)
==75==
==75== 16 bytes in 1 blocks are definitely lost in loss record 2 of 3
==75==    at 0x4C3217F: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==75==    by 0x1091A7: main (crtp_leak.cpp:64)
==75==
==75== 24 bytes in 1 blocks are definitely lost in loss record 3 of 3
==75==    at 0x4C3217F: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==75==    by 0x1091C5: main (crtp_leak.cpp:65)
==75==
==75== LEAK SUMMARY:
==75==    definitely lost: 56 bytes in 3 blocks
==75==    indirectly lost: 0 bytes in 0 blocks
==75==      possibly lost: 0 bytes in 0 blocks
==75==    still reachable: 0 bytes in 0 blocks
==75==         suppressed: 0 bytes in 0 blocks
==75==
==75== For counts of detected and suppressed errors, rerun with: -v
==75== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)

1
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,554
16.03.2021, 20:20
DrOffset, спасибо... начинаю понимать, как создаётся язык (что и есть цель ООП по сравнению с процедурным пр-ем), паттерны и Finite State Machine ... - прямо откровения от автора ... интересные... особенно понравилась фраза
baseFSM class provides a framework for programmer
я тогда посоветую ещё - Федор Г. Пикус | Идиомы и паттерны проектирования в современном С++ (2020) [PDF] - может здесь брала... стр 274-276 хорошо описаны ограничения CRTP классического и расширенного основным класслм (как описано в вашей pdf и как я пыталась кодом выше) -
Pros:
1) шаблон генерит функции для потомков авоматически, чтобы их не писать во всех потомках - в классическом варианте
2) по расширенной версии с базовым классом... использование перекрёстного приведения (своеобразный dynamic-cast)
Если во время выполнения выяснится, что фактический производный объект имеет тип, не являющийся комбинацией обоих базовых классов, то dynamic_cast завершится неудачно и вернёт NULL (или возбудит исключение, если мы используем не указатели, а ссылки)
- "обоих базовых классов" - это базового и template'ового... в вашей pdf в принципе, о том тоже указано...
вообще, интересный трюк - наследоваться от базового и от template'ового... - наверно, даже таким способом и страховку от "алмаза смерти" можно изобрести?... не пробовала ещё...
только вот получить наследника второй очереди - с этим наследуемым виртуальным clone(), задаваемым в шаблоне, чтобы не прописывать его во всех наследниках, - уже вроде не получится ....

Добавлено через 6 минут

P.S.
Кликните здесь для просмотра всего текста
Цитата Сообщение от GbaLog- Посмотреть сообщение
==75== 16 bytes in 1 blocks are definitely lost in loss record 1 of 3
==75== at 0x4C3217F: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==75== by 0x109189: main (crtp_leak.cpp:63)
==75==
==75== 16 bytes in 1 blocks are definitely lost in loss record 2 of 3
==75== at 0x4C3217F: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==75== by 0x1091A7: main (crtp_leak.cpp:64)
==75==
==75== 24 bytes in 1 blocks are definitely lost in loss record 3 of 3
==75== at 0x4C3217F: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==75== by 0x1091C5: main (crtp_leak.cpp:65)

значит new от строк 63-65 надо потом delete.. т.е. они, вероятно, не от-move-ились в unique_ptr, а, наверно, от-copy-лись... простите за выражения
0
17.03.2021, 07:09

Не по теме:

Цитата Сообщение от JeyCi Посмотреть сообщение
т.е. они, вероятно, не от-move-ились в unique_ptr
а что и куда у вас должно "отмувнуться"? не вижу такого когда у вас.

0
17.03.2021, 07:31

Не по теме:


Цитата Сообщение от JeyCi Посмотреть сообщение
Shape(Shape&&) = default; // ? конструктор перемещения
//====
std::unique_ptr<AbstractShape> // родительский ptr в unique заворачивается...
вообще, действительно, как-то не прозрачно... но тема конструкторов, наверно, уже др. тема... или делать явный std::move ...
спасибо, что прогнали через Valgrind

0
17.03.2021, 07:31

Не по теме:

JeyCi, утечка там вот тут:

Code
1
2
3
4
5
std::unique_ptr<AbstractShape> clone() const override
{
     return std::make_unique<Derived> //создаётся НОВЫЙ объект обёртки
        (static_cast<Derived const&>(*this));//в конструктор передаётся КОПИЯ *this - снаружи this не удалится сам, так как создан new
}

0
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,554
18.03.2021, 08:57
Цитата Сообщение от DrOffset Посмотреть сообщение
CRTP должен быть элементом дизайна, а не оптимизации.
Нет никакого смысла вводить его только ради оптимизации. Должны быть более фундаментальные причины.
? вижу только одну возможную фундаментальную причину - не дублировать код в потомках (чтобы было легче сопровождать) и - вторую - не отдавать полиморфизм на откуп run-time'у (для скорости)... имхо
p.s.
для меня могут быть только 4 фундаментальные причины:
- для увеличения скорости,
- для минимизации памяти,
- для минимизации писанины,
- для того, чтобы не потерять что-нибудь (что приводит к memory leaks)...
разве есть ещё какие-то более фундаментальные причины, например для использования CRTP?..
0
19506 / 10109 / 2464
Регистрация: 30.01.2014
Сообщений: 17,834
18.03.2021, 09:16
Цитата Сообщение от JeyCi Посмотреть сообщение
для увеличения скорости,
Обычно там, где действительно нужен runtime-полиморфизм, никак не получится его заменить на compile-time.

Цитата Сообщение от JeyCi Посмотреть сообщение
разве есть ещё какие-то более фундаментальные причины
Я говорил только про выбор CRTP в качестве решения для замены runtime-полиморфизма.
И суть моих слов в том, что дизайн должен быть основным критерием, а не производительность. В смысле, что производительность - это следствие, а не первопричина.
0
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,554
18.03.2021, 13:07
Цитата Сообщение от DrOffset Посмотреть сообщение
CRTP должен быть элементом дизайна, а не оптимизации
ну в общем, да, - если по логике нужны будут разные реализации от одного интерфейса... то CRTP расширенный очень даже хорош (хоть некоторые и пеняют на "читаемость и отлаживаемость кода" по сравнению с использованием обычных Абстрактных классов )...
Единственная ситуация, когда вам действительно нужно использовать динамический полиморфизм, — это когда реализация недоступна во время компиляции; например, когда он загружен из динамической библиотеки.
- вот я пока останусь при такой точке зрения...
спасибо за view: performance <-design-> optimization (& 1<->3)
0
18.03.2021, 15:45

Не по теме:

Да хорош тему засерать и тролиху кормить.

0
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,554
23.03.2021, 18:40
Цитата Сообщение от Алексей1153 Посмотреть сообщение
Зачем метод clone?
вот читаю книгу из #25 - так речь о CRTP-фабрике в главе 13 - там и примеры с clone()... а сам CRTP в главе 8 описывается... а wiki, наверно, вырвали кусок и этот clone() не заменили на любую более вразумительную функцию...
только сейчас поняла, почему clone() - рудимент от фабрики - может быть любая др. функция...
0
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,554
18.05.2021, 19:55
да, с CRTP-фабрикой, - примером с wiki, - я всё-таки поспешила...
Цитата Сообщение от DrOffset Посмотреть сообщение
CRTP должен быть элементом дизайна, а не оптимизации.
Нет никакого смысла вводить его только ради оптимизации. Должны быть более фундаментальные причины.
всё-таки смысл статического полиморфизма (в данном случае) - Lazy: CRTP...
That is possible because the method will be instantiated when called.
или здесь...
===
- полагаю, желание/потребность подрядить ленивые вычисления/методы и может стать фундаментальным аргументом в пользу выбора CRTP (иных пока не вижу)...
только я пока не выбирала ленивые методы... как бы не вижу в них преимуществ... разве что по памяти (чтобы функции-члены не инстанцировались в случае, если вдруг потом могут и не понадобится)... имхо

Добавлено через 4 минуты
p.s.
вероятно, для подмешивания этот трюк в основном используется... так же
MixIn функциональность не обязательно должна быть включена внутрь некоторого класса. Иногда возможно ее реализовать в виде свободной функции
0
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,554
19.05.2021, 10:42
MixIn функциональность не обязательно должна быть включена внутрь некоторого класса. Иногда возможно ее реализовать в виде свободной функции
хотя, как справедливо подмечено, - просто ради удобства лучше инкапсулировать
With the CRTP, you can see that Sensitivity offers the interface of NumericalFunctions...
And with the template non-member functions you don’t. They would be hidden behind a #include somewhere.
===
Цитата Сообщение от JeyCi Посмотреть сообщение
для подмешивания
оставлю работающий код (с линка - просто там нарезки) для ситуации подмешивания нескольких Базовых классов
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// https://habr.com/ru/post/210894/
 
// Возможно, вы заметили в предыдущих главах “Явный интерфейс” и “MixIn наоборот” я использовал открытые функции в производном классе. Вообще говоря, это не очень хорошо, так как нарушает инкапсуляцию. Получается, что наружу у нас “торчат” функции, которые не предназначены для того, что пользователь вызывал их напрямую. 
//Можно решить эту проблему, сделав базовые классы друзьями производного. После этого можно вносить эти функции в private секцию, но представьте, что вам нужно отнаследовать от нескольких базовых MixIn’ов. Придется делать друзьями все базовые классы. Для комплексного решения этой проблемы, а также для того, чтобы обеспечить компиляцию на некоторых старых компиляторах, можно ввести новый уровень косвенности. Он представляет из себя структуру, функции которой перенаправляют вызовы из базы в производный класс.
 
#include <iostream>
 
using namespace std;
 
//  можно ввести новый уровень косвенности. Он представляет из себя структуру, функции которой перенаправляют вызовы из базы в производный класс.
// indirection level
struct access
{
    template<typename Impl>
    static void on_handle_connect(Impl* impl) {impl->handle_connect();}
 
    template<typename Impl>
    static void on_handle_response(Impl* impl) {impl->handle_response();}
};
 
// Теперь из базовых классов, мы вызываем не функции производного, а функции промежуточной структуры.
// BASE
template<typename D>
struct connection_handler
{
    // ...
    void on_connection()
    {
        access::on_handle_connect(static_cast<D*>(this));
    }
};
 
template<typename D>
struct response_handler
{
    // ...
    void on_response()
    {
        access::on_handle_response(static_cast<D*>(this));
    }
};
 
// В производном же классе нам достаточно внести в друзья только структуру access.
// DERIVED
class combined_handler : public connection_handler<combined_handler>, 
public response_handler<combined_handler>
{
    private:
        friend struct access;
        void handle_connect(){ std::cout << "handle_connect: " << __PRETTY_FUNCTION__ << std::endl; }
        void handle_response(){ std::cout << "handle_response: " << __PRETTY_FUNCTION__ << std::endl; }
};
 
 
int main()
{
    combined_handler s1;
 
    s1.on_connection();
    s1.on_response();
   
}
/*
handle_connect: void combined_handler::handle_connect()
handle_response: void combined_handler::handle_response()
*/

- всё-таки доп. уровень косвенности в CRTP через друзей может помочь и избежать "Алмаза смерти" (подробнее здесь - смысл friend в подмешивании)...
===
и так же (по последнему линку) - это попытка избавиться от большого количества static_cast'ов при реализации CRTP-паттерна, которая как раз и заключается в выносе всех static_cast'ов на верх. уровень иерархии, а чтобы оттуда не получить ромбовидного наследования - использование template'а, принимающего параметром тоже template (а не конкретный type)
Note that the template parameter is not just a typename, but rather a template<typename> class. This simply means that the parameter is not just a type, bu rather a template itself, templated over a type whose name is omitted. For example crtpType can be
===
в общем, CRTP, конечно, вариант, когда все типы известны на этапе компиляции, - для статического полиморфизма... но всё-таки глубокие иерархии всё равно не стоит делать... а диспетчеризация через visit и variant в std даёт нужное и без иерархий... появление std::variant -- всё-таки большой шаг вперёд был в std... имхо
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
19.05.2021, 10:42

Английские идиомы: как правильно перевести in its own right?
Как правильно перевести in its own right? Например, вот в таком контексте: Добавлено через 3 минуты В русском переводе книги...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
35
Ответ Создать тему
Новые блоги и статьи
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru