1 | |||||||
С++ идиомы31.07.2016, 19:20. Показов 120148. Ответов 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
|
31.07.2016, 19:20 | |
Ответы с готовыми решениями:
34
С++ идиомы - обсуждение Как и какие идиомы и паттерны можно (и лучше) применять? Идиомы программирования Английские идиомы: как правильно перевести in its own right? Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
01.08.2016, 11:33 | 2 | |||||
Scope Guard
Задачи: Гарантировать освобождение ресурсов при возникновении исключения, но не освобождать ресурсы при нормальном завершении. Предоставить базовую гарантию безопасности исключений. Мотивация: Идиома RAII позволяет захватывать ресурсы в конструкторе и освобождать их в деструкторе, при достижении конца области видимости или из-за исключения. В RAII ресурс освобождает всегда. Это может быть не очень гибким решением. Может потребоваться освободить ресурсы в случае возникновения исключения и не освобождать при нормальном завершении. Решение и пример кода: Типичная реализация идиомы RAII с проверкой необходимости освобождения ресурса.
9
|
01.08.2016, 11:54 [ТС] | 3 | ||||||||||
self-assignment in an assignment operator (самоприсваивание в операторе присваивания)
T::operator= который обрабатывает случай, где левый и правый операнды являются одним и тем же объектом.
Понимайте разницу между идентичностью (левый и правый операнды являются одним объектом) и одинаковостью (левый и правый операнды имеют одинаковые значения).T::operator= должен защищать себя в случае индетичности объектов, код присваивания может быть удобным и безопастным предполагая, что работает с разными объектами. Существуют и другие техники, которые в некоторых случаях могут быть более удобными, но они не применимы во всех ситуациях. Например если все члены класса T (скажем mem1, mem2, ..., memN) предоставляют функцию swap(), то можно использовать следующий код
6
|
01.08.2016, 20:51 | 4 | ||||||||||
Shrink-to-fit (уменьшить до размеров)
Задачи: Уменьшить ёмкость (capacity) контейнера, до размера, достаточного для содержания элементов. Также известен как "Swap-To-Fit", введенный Скотом Майерсом в книге "Effective STL" ("Эффективное использование STL"). Мотивация: Контейнеры в стандартной библиотеке часто выделяют памяти под большее число элементов, чем находится в контейнере. Это позволяет оптимизировать расширение контейнера за счет более редких выделений памяти. Но, когда контейнер уменьшается (или когда запас израсходаван не полностью, прим. переводчика), память так и остается занятой, хотя, фактически, она не используется. Это не нужный перерасход памяти. Данная (shrink-to-fit) идиома была разработана чтобы уменьшить расход до минимального требуемого контейнеру количества памяти, тем самым экономя ресурсы. Решение и пример кода: Данная идиома очень проста, как показано ниже.
std::vector<int>(v) , создает временный вектор целых чисел, гарантируя, что выделенной памяти достаточно для хранения всех элементов вектора v, который передан в параметре. Также эти элементы копируются во временный вектор.Вторая половина инструкции - .swap(v) обменивает элементы вектора v и временного вектора, используя не выбрасывающую исключений функцию-член swap, что является очень эффективным средством, которое сводится к обмену внутренних указателей между векторами или чуть более того. После этого временный вектор удаляется, очищая память и удаляя элементы, которые первоначально находились в векторе v. Вектор v же имеет ровно столько памяти, сколько нужно для хранения элементов. ISO/IEC 14882:1998 не гарантирует такое поведение для конструктора копирования. Как гарантировать такое поведение? Более надежным решением (в частности std::string и std::vector могут быть реализованы с использованием подсчета ссылок и тогда конструктор копирования может "скопировать" всю избыточную память) будет использование конструктора диапазонов, вместо конструктора копирования:
В C++11 некоторые контейнеры предоставляют функцию-член shrink_to_fit, например vector, deque, basic_string. shrink_to_fit запрашивает уменьшение capacity до size, Но данный запрос не является обязательным к исполнению.
8
|
01.08.2016, 20:51 | 5 | |||||||||||||||||||||||||
Checked delete
Цель: Повышение безопасности при использовании delete expression. Мотивация и пример проблемного кода: Стандарт C++ (пункт 5.3.5/5) позволяет использовать в delete-expression указатель на не полный тип, но при этом, если деструктор или функция освобождения памяти объекта не являются тривиальными, то это приведет к неопределенному поведению.
Сообщение от 5.3.5/5
В следующем примере в main.cpp определяется объект типа Object. В функции main() вызывается функция delete_object(), определенная в deleter.cpp, где нет определения класса Object, а есть лишь его объявление. Вызов delete в данной функции приводит к неопределенному поведению.
Идиома checked delete полагается на вызов шаблонной функции для удаления объекта, а не на прямой вызов delete, который может привести к неопределенному поведению для объявленных, но неопределенных типов. Ниже приводится реализация шаблонна функции boost::checked_delete из Boost Utility library.Её использование вызывает ошибку компиляции при использовании sizeof для параметра шаблона T, если T - не полный тип. Если T объявлен, но не определен, то sizeof(T) будет генерировать ошибку компиляции или возвращать нулевое значение, в зависимости от компилятора. Если sizeof(T) вернет ноль, то произойдет ошибка компиляции, т.к. объявляется массив с отрицательным количеством элементов (-1). Имя type_must_be_complete в данном случае появляется в сообщении об ошибке и позволяет понять что произошло.
delete[] .Предупреждение: std::auto_ptr не использует никакого эквивалента checked delete. Поэтому инстанцирование std::auto_ptr с неполным типом может привести к неопределенному поведению в деструкторе, если в момент объявления std::auto_ptr тип параметра шаблона определен не полностью.
12
|
02.08.2016, 08:12 [ТС] | 6 | ||||||||||||||||||||||||||||||
Pointer To Implementation (pImpl)
Идиома "pointer to implementation" (pImpl) также называется "opaque pointer" (дословный перевод "непрозрачный указатель"), это способ предоставления данных и в еще один уровень абстракции в реализации классов. В С++ вы должны написать декларацию переменных-членов класса внутри определения класса, эти члены должны быть публичны (прим. переводчика - думаю речь идет об интерфейсе, иначе зачем членам быть публичными) и поскольку для членов выделяется память абстракция реализации не возможна для "всех" классов. Тем не менее, за счет дополнительного указателя и вызова функции, вы можете иметь такой уровень абстракции через указатель на реализацию. Допустим вы написали такой класс:
pImpl может реализовывать следующий паттерн таким образом, что описанная выше ситуация не является проблемой.
8
|
☆ Форумчанин(FSC)☆
|
|||||||||||
09.08.2016, 19:40 | 7 | ||||||||||
Получение адреса(ака взятие адреса aka Address-of)
Назначение: Поиск адреса обьекта класса который имеет перегруженный унарный оператор "амперсанд"(&). Интерес: Язык С++ разрешает перегрузку унарного амперсанда (&) для классовых типов. Тип возвращаемого значения не обязательно должен быть реальным адресом обьекта . Предназначение такого класса довольно спорно, но все же язык позволяет это.Идиома взятия адреса это способ получения реального адреса обьекта, независимого от перегруженного унарного амперсанда и его инкапсулированости. В примере ниже не удается скомпилировать функцию main потому что оператор & класса nonaddressable является закрытым членом этого класса.
Идиома получения адреса запрашивает адрес обьекта используя серию преобразований
Используется в библиотеке boost для получения адреса Эта функция уже пристутствует в заголовке <memory> нового стандарта C++(C++ 11)
2
|
161 / 153 / 92
Регистрация: 18.11.2015
Сообщений: 677
|
||||||||||||||||||||||||||||||||||||
16.08.2016, 15:46 | 8 | |||||||||||||||||||||||||||||||||||
Nullptr
Задачи: Научиться отличать число 0 от нулевого указателяМотивация: На протяжении многих лет С++ имело позорный недостаток, у С++ не было ключевого слова, которое бы обозначало нулевой указатель. С++ 11 избавился от этого недостатка. Строгая типизация С++ делает определение глобальной константы NULL в стиле языка C почти что бесполезной в выражениях, например:
Проблема самого первого примера в том, что С++ запрещает приведение из типа void * , даже когда его значение является константным нулем. Но, для простого константного нуля С++ имеет преобразование int в указатель (еще short в указатель , long в указатель и т.п.).Это имеет свои минусы. Приведем пример на работе с перегруженными функциями:
main превратиться в:
Код
Double * Int #define NULL 0 так, как задумывалось (с указателями), нужно всегда писать что типа static_cast<double *>(NULL) Использование #define NULL 0 имеет свою кучку проблем. Помимо проблемы с перегруженными функциями, C++ требует того, чтобы NULL было определено целочисленным константным выражением со значением 0. Поэтому, в отличии от С, нулевой указатель не может быть определен как ((void *)0) в стандартной библиотеке C++. Более того, конкретная форма определения оставлена для той или иной реализации, что значит, что 0 и 0L - подходящие определения, наряду с некоторыми другими.Решение и пример использования Идиома нулевого указателя решает некоторые вышеперечисленные проблемы и может быть использована снова и снова. Будущий пример является очень близким по функционалу решением, относительно ключевого слова nullptr , добавленного в С++ 11, и использует только стандартные приемы, которые были доступны еще до С++ 11.
#include класса выше)
nullptr с указателем на функцию-член (pmf ). Код выше успешно компилируется, если убрать строки с ошибками, которые мы допустили в демонстрационных целях (26, 31, 34, 35, 40, 41, 42, 50)Заметьте, что идиома нулевого указателя использует идиому Return Type Resolver, чтобы автоматически вывести нулевой указатель правильного типа, в зависимости от типа объекта, к которому мы его присваиваем. Например, если nullptr присваивают к char * , создается функция преобразования с char параметром шаблона.Последствия Есть некоторые недостатки этого приема, в список этих недостатков входят следующие пункты:
5
|
Мозгоправ
|
|||||||||||||||||||||
03.11.2019, 18:47 | 9 | ||||||||||||||||||||
Iterator Pair
Итераторная пара Задача Определить диапазон значений данных, без привязки к базовой структуре, которая используется этими значениями. Также известно как Иногда это называют итераторным диапазоном (Iterator Range). Проблема Хорошо известно, что для создания вектора vector<int> из другого vector<int> используется конструктор копии. Также для создания вектора vector<int> из другого vector<int> можно использовать идиому Приведение типа посредством шаблонного метода (Coercion by Member Template), применённую к конструктору шаблонного члена. Пример кода показан ниже.
Решение и пример кода Пара итераторов используется для обозначения начала и конца диапазона значений. Благодаря шаблону проектирования итераторов, кто бы ни использовал эту идиому (в нашем примере для вектора), может получить доступ к диапазону, абстрагируясь от деталей реализации структуры данных. Единственное требование заключается в том, что итераторы должны предоставлять минимальный фиксированный интерфейс. Например, предоставлять оператор префиксного инкремента.
set<T>::iterator или list<T>::iterator или массив POD. Независимо от типа, любой общий алгоритм, написанный в терминах итераторных пар, работает. Часто полезно показать, что модель должна реализовывать итераторные типы. В приведенном выше примере итераторы требуют от модели наличия как минимум InputIterator . Более подробная информация о категориях (тегах) итераторов и их использовании описана в идиоме Диспетчеризация тегов.Иногда без использования идиомы итераторной пары обойтись невозможно. Например, при создании std::string из буфера символов, в котором присутствуют нулевые символы, применение идиомы итераторной пары просто необходимо.
Все стандартные контейнеры. Связанные идиомы
1
|
Мозгоправ
|
||||||||||||||||
05.11.2019, 14:53 | 10 | |||||||||||||||
Coercion by Member Template
Приведение типа посредством шаблонного метода Задача Повысить гибкость интерфейса шаблонного класса, позволяя шаблону класса участвовать в тех же неявных преобразованиях типов, что и его типы-параметры. Проблема Часто бывает полезно расширить отношения между двумя типами до специализации шаблонов классов с этими типами. Например, предположим, что класс D наследуется от класса B . Указатель на объект класса D может быть присвоен указателю на класс B . C++ поддерживает это неявным образом. Однако типы, составленные из этих типов, не разделяют отношения родительских типов. Это относится и к шаблонам классов, поэтому объект Helper<D> обычно нельзя присвоить объекту Helper<B> .
std::unique_ptr<D> в std::unique_ptr<B> . Это интуитивно понятно, но не поддерживается без использования идиомы Приведение типа посредством шаблонного метода.Решение и пример кода Определите в шаблонном классе шаблонные методы, которые полагаются на неявные преобразования типов, которые поддерживаются типами параметров. В следующем примере шаблонный конструктор и оператор присваивания работают для любого типа U , для которого разрешена инициализация или присвоение T* из U* .
D унаследован от класса B , D-объект является B-объектом. Однако массив объектов D не является массивом объектов B . Это запрещено в C++ из-за возможного неправильного вычисления размера массива на основании размера элемента. (Объект производного класса, скорее всего, будет занимать больше памяти, чем объект базового класса. Поэтому если предположить, что массив D-объектов, это массив B-объектов, то часть массива будет утеряна при расчёте объёма занимаемой памяти, исходя из размера B-объекта, а остальные объекты, за исключением первого, будут некорректны из-за неправильного позиционирования на начало объекта. – прим. перев.) Ослабление этого правила для множества указателей может быть полезным. Например, массив указателей на D должно быть возможно присвоить массиву указателей на B (при условии, что деструктор B является виртуальным). Этого можно достичь с помощью рассматриваемой идиомы, но требуется дополнительная осторожность, чтобы предотвратить копирование массива указателей на базовый тип в массив указателей на производный тип. Для этого можно использовать специализации шаблонных методов или SFINAE.В следующем примере используется шаблонный конструктор и шаблонный оператор присваивания. Из-за объявления Array<U *> они будут разрешать копирование массивов указателей только тогда, когда типы элементов различаются.
std::unique_ptr и std::shared_ptr , используют эту идиому.Предостережения Типичной ошибкой в реализации идиомы Приведения типа посредством шаблонного метода является отсутствие нешаблонного конструктора копирования или нешаблонного копирующего оператора присваивания при наличии шаблонного конструктора копирования и шаблонного копирующего оператора присваивания. Компилятор автоматически создаёт конструктор копирования и копирующий оператор присваивания, если класс не объявляет их, что может вызвать скрытые и неочевидные ошибки при использовании этой идиомы. Известные применения
Связанные идиомы
1
|
329 / 149 / 33
Регистрация: 29.06.2019
Сообщений: 1,429
|
|
12.02.2021, 16:38 | 12 |
доп. на habr'e
----------- добавлю линк на pdf - про Exception Safety, включая RAII - Using Exceptions | C++ - using RAII] for cleanup ... вообще Exception Safety - очень интересная тема - очень нравится идея ===== Добавлено через 11 минут CRTP, насколько понимаю... но есть один нюанс - чтобы, действительно, добиться полиморфного поведения от объектов классов, создаваемых на основе шаблона во время компиляции, - т.е. чтобы их можно было помещать в контейнер<T*>, - надо всё-таки ещё создать абстрактный класс, от которого и унаследовать шаблон... - см. Polymorphic copy construction... поэтому нужен вам или не нужен этот шаблон - это ещё вопрос... хотя заменить динамический полиморфизм статическим (там где это возможно) - вобщем-то неплохо для app performance Добавлено через 28 минут ===== спорная трактовка pImpl (точнее перевод на рус.яз.)... обычно private сектор класса можно оформить отдельным классом и использовать указатель на него в основном классе, а подключить его обычным #include impl.h (интерфейс), понятное дело, у которого может быть свой .c (реализация)... такое сокрытие private полей и методов (кстати, понятное дело, что будет больше кода) , действительно, полезно (писать этот ворох кода), когда, например, профилировщик класса показывает, что создание его (например, с большим количеством полей) является узким местом в вашем коде... в частности, при разработке библиотек и тем более кросс-платформенных - разработчику быстрее будет перекомпилировать проект если разделены зависимости между private и public частями основного интерфейса (.h-файл) и изменения внесены только в реализацию скрытого класса... то и не будут перекомпилироваться все пользователи его, а их может быть несколько, в частности при разработке кроссплатформенной версии библиотеки... в Qt часто используется идиома pImpl для Widget'ов, например, для описания родительского окна и его потомков... в используемом мной U++ это не совсем актуально в таком разрезе, поскольку наследования ЭУ как такового нет (они все независимы - главное правильно расставлять конструкторы и деструкторы, согласно RAII, полагаю)... имхо и кстати, используя pImpl, - вы теряете возможность использовать inline (хотя последнего современные компиляторы в принципе воспринимают как попало)... и вижу пользу в использовании идиомы pImpl - например, при создании части интерфейса на C++ с выносом этой части в отдельную реализацию, чтобы основная часть основного класса, написанного на С, могла использовать этот свой stuff на С++ ... - т.к. правила дурного тона - смешивать C и C++ и неуважение к компилятору смешивать языки... имхо в общем, часто городить pImpl - это просто усложнять себе сопровождаемость кода, но обоснованное использование принесёт свои удобства... имхо Добавлено через 19 минут конечно, можно разделить интерфейс и реализацию и с помощью чисто абстрактного класса, но тогда мы вынуждены иметь дело с vtable в run-time'e ... но, используя идиому pImpl и уходя от необходимость иметь дело с vtable в run-time'e, улучшим ли мы performance нашего app, - спорно и не всегда, если нам всё равно приходится выделять доп. память под скрытый объект в придачу к основному объекту... + сокрытие части реализации в др. классе, требует подробного описания возможных побочных эффектов этой скрытой части на основной класс хотя бы в документации... вот как-то так Добавлено через 3 минуты ведь всегда интересно WHEN to use и каковы Последствия
0
|
Неэпический
|
|
14.02.2021, 12:22 | 13 |
Как-то странно не сказать о том, что программа должна быть еще и запущена перед тем, как будет выброшено исключение.
RAII - отдельный от исключений механизм, конечно же всегда и программа должна быть запущена и исключение перехвачено и всё остальное должно быть правильно. Что касается std::terminate, то он вызывается, но вот остальное зависит от реализации. http://eel.is/c++draft/except#handle-9
0
|
329 / 149 / 33
Регистрация: 29.06.2019
Сообщений: 1,429
|
|
14.02.2021, 13:08 | 14 |
ну не стоит же этого забывать - в др. языках всё, что угодно, и само может выскакивать - в более высокоуровневых... а тут в try{} catch(...){} надо не забыть обернуть, чтобы выскочило...
0
|
329 / 149 / 33
Регистрация: 29.06.2019
Сообщений: 1,429
|
||||||
14.03.2021, 16:53 | 16 | |||||
действительно, как-то разорвано всё на wiki... простое наследование от Астахова - в стиле CRTP с возможностью использовать объекты в полиморфном контейнере - рабочий вариант так:
Кликните здесь для просмотра всего текста
при этом передали rowPointer в std::unique_ptr и удалили при выходе из scope...
критические замечания всегда приветствуются... лучше кодом Добавлено через 19 минут и наблюдения:
0
|
фрилансер
5854 / 5394 / 1103
Регистрация: 11.10.2019
Сообщений: 14,405
|
|
14.03.2021, 20:26 | 17 |
утечка же
Добавлено через 2 минуты я бы поопасался тут делать rvalue ссылку
1
|
329 / 149 / 33
Регистрация: 29.06.2019
Сообщений: 1,429
|
||||||
14.03.2021, 20:36 | 18 | |||||
а я думала, что unique_ptr действует, как обёртка, когда помещаем в неё... и в debug на break_point после выхода из scope, вроде, не увидела левых pointers - вот и подумала, что всё норм.? ...
но, полагаю, можно и так
наверно, на pointer'ах rvalue ссылку лучше не делать - приму на заметку!... &
0
|
фрилансер
5854 / 5394 / 1103
Регистрация: 11.10.2019
Сообщений: 14,405
|
|
14.03.2021, 20:43 | 19 |
JeyCi, да, я слегка ошибся - у тебя запутанная архитектура ) Утечки не будет
но зачем такие пляски, если вместо new сразу создать умный указатель через make_unique? Зачем метод clone? Добавлено через 54 секунды в данном цикле нужно просто константную ссылку. А переместиться может не только поинтер, а объект любого класса Добавлено через 2 минуты ещё у меня опасение, что мы тут оффтопим
0
|
329 / 149 / 33
Регистрация: 29.06.2019
Сообщений: 1,429
|
|
14.03.2021, 21:05 | 20 |
потому что по тому примеру с wiki (куда оставляла линк) - там помимо template'a ещё и Abstract Class - чтобы нормально в полиморфный контейнер входило... в принципе там всё описано по линку, но примеры уж очень разорванные и потому некомпилируемые - поэтому и выложила рабочую версию...
часто CRTP описывается только с template'ом и наследниками - а дальше пляски и не всегда работает, как положено... в частности полиморфное поведение в полиморфном контейнере... ещё потестить можно обычные примеры, но этот про запас не помешает... возможно, в любом случае спасибо за ваш view
0
|
14.03.2021, 21:05 | |
|
Новые блоги и статьи | |||||
Это работает. Скорость асинхронной логики велика. Вопрос видимо останется в стабильности. Плата - огонь!
Hrethgir 13.01.2025
По прошлому проекту в Logisim Evolution https:/ / www. cyberforum. ru/ blogs/ 223907/ blog8781. html прилагаю файл архива проекта Gowin Eda и снимок. Восьмибитный счётчик из сумматора+ генератор сигнала. . .
|
UserScript для подсветки кнопок языков программирования в зависимости от текущего раздела
volvo 13.01.2025
В результате работы этого скрипта подсвечиваются нужные кнопки не только в форме быстрого ответа, но и при редактировании сообщения:
/ / ==UserScript==
/ / @name CF_DefaultLangSelect
/ / . . .
|
Введение в модели и алгоритмы машинного обучения
InfoMaster 12.01.2025
Машинное обучение представляет собой одну из наиболее динамично развивающихся областей искусственного интеллекта, которая фокусируется на разработке алгоритмов и методов, позволяющих компьютерам. . .
|
Как на Python создать нейросеть для решения задач
InfoMaster 12.01.2025
В контексте стремительного развития современных технологий особое внимание уделяется таким инструментам, как нейросети. Эти структуры, вдохновленные биологическими нейронными сетями, используются для. . .
|
Как создать нейросеть для генерации картинок на Python
InfoMaster 12.01.2025
Генерация изображений с помощью искусственных нейронных сетей стала одним из наиболее захватывающих направлений в области компьютерного зрения и машинного обучения. В этой статье мы рассмотрим. . .
|
Создание нейросети для генерации текста на Python
InfoMaster 12.01.2025
Нейросети, или искусственные нейронные сети, представляют собой модели машинного обучения, вдохновленные работой человеческого мозга. Они состоят из множества взаимосвязанных узлов, или "нейронов",. . .
|
Как создать нейросеть распознавания изображений на Python
InfoMaster 12.01.2025
Введение в распознавание изображений с помощью нейросетей
Распознавание изображений с помощью нейронных сетей стало одним из самых впечатляющих достижений в области искусственного интеллекта. Эта. . .
|
Основы искуственного интеллекта
InfoMaster 12.01.2025
Искусственный интеллект (ИИ) представляет собой одну из наиболее динамично развивающихся областей современной науки и технологий. В широком смысле под искусственным интеллектом понимается способность. . .
|
Python и нейросети
InfoMaster 12.01.2025
Искусственные нейронные сети стали неотъемлемой частью современных технологий, революционизировав множество областей - от медицинской диагностики до автономных транспортных средств. Python, благодаря. . .
|
Python в машинном обучении
InfoMaster 12.01.2025
Python стал неотъемлемой частью современного машинного обучения, завоевав позицию ведущего языка программирования в этой области. Его популярность обусловлена несколькими ключевыми факторами, которые. . .
|
Создание UI на Python с TKinter
InfoMaster 12.01.2025
TKinter — это одна из наиболее популярных библиотек для создания графических интерфейсов пользователей (GUI) в языке программирования Python. TKinter входит в стандартную библиотеку Python, что. . .
|
HTML5 в разработке мобильных приложений
InfoMaster 12.01.2025
Введение: Обзор роли HTML5 в мобильной разработке
В современном мире мобильных технологий HTML5 стал ключевым инструментом для разработки кроссплатформенных приложений. Эта технология произвела. . .
|