Comments 24
Как раз читаю Effective C++ Мейерса. RAII и умные указатели — действительно отличная вещь, во многом облегчающая жизнь.
Вместо того, чтобы полагаться или не полагаться на сгенерированные компилятором функции, можно ему явно запретить генерацию. В C++11 для этого есть "=delete":
Вместо того, чтобы полагаться или не полагаться на сгенерированные компилятором функции, можно ему явно запретить генерацию. В C++11 для этого есть "=delete":
Singleton
class Singleton {
public:
Singleton(const Singleton& rhs) =delete;
Singleton& operator=(const Singleton& rhs) =delete;
static Singleton *getInstance() {
return instance_;
}
private:
Singleton();
static Singleton *instance_;
};
мутексРезануло глаза. В русскоязычной литературе всё-таки «мьютекс» обычно пишут.
Красивше такой вариант:
static auto instance() {
static singleton instance{};
return &instance;
}
Хотя я возвращал бы ссылку, копирование все равно запрещено.
static auto instance() {
static singleton instance{};
return &instance;
}
Хотя я возвращал бы ссылку, копирование все равно запрещено.
А глобальная ссылка позволит обращаться к объекту проще.
Ещё требуется указать, что эта переменная одна общая для всех cpp-файлов, использующих наш Singleton.h. Например в MSVC это так:
Singleton & singletonThe = Singleton::Instance();
Ещё требуется указать, что эта переменная одна общая для всех cpp-файлов, использующих наш Singleton.h. Например в MSVC это так:
__declspec(selectany) Singleton & singletonThe = Singleton::Instance();
«Нужно больше глобальных переменных».
Идея не встретила одобрения. Забавно.
Коллеги, вы предпочитаете повсюду писать
Коллеги, вы предпочитаете повсюду писать
Singleton::Instance()
вместо singletonThe
– два идентификатора вместо одного? Или какая-то другая причина?__declspec(selectany) — это какбэ не портабельный C++. Плюс к тому, здесь не ленивая инициализация, а порядок инициализации глобальных переменных в C++ — это просто-таки поле из граблей.
Атрибут
Не поддерживается в Intel C++. Однако его используют около 2% присутствующих (из пишущих на С++) – результаты опроса.
А неудачный порядок инициализации глобальных переменных выявляется сам собой, если в нашем проекте есть самый минимальный набор автоматических тестов. К моменту входа в
В нашем проекте так много классов с паттерном Одиночка (Singleton), что можно запутаться в порядке их инициализации. Значит это не мелкая поделка, а большой проект, а значит и автоматические тесты в нём конечно же есть.
Зная всё это, спросите себя, согласны ли вы вдвое ухудшить читабельность везде, где происходит обращение к объекту класса Singleton.
__declspec(selectany)
поддерживается и в gcc, и в Borland C++, и в Clang с ключом -fms-extensions
.Не поддерживается в Intel C++. Однако его используют около 2% присутствующих (из пишущих на С++) – результаты опроса.
А неудачный порядок инициализации глобальных переменных выявляется сам собой, если в нашем проекте есть самый минимальный набор автоматических тестов. К моменту входа в
main
глобальные переменные должны быть инициализированы. Практически любой тест должен бы достигать этой точки.В нашем проекте так много классов с паттерном Одиночка (Singleton), что можно запутаться в порядке их инициализации. Значит это не мелкая поделка, а большой проект, а значит и автоматические тесты в нём конечно же есть.
Зная всё это, спросите себя, согласны ли вы вдвое ухудшить читабельность везде, где происходит обращение к объекту класса Singleton.
По-моему мутные глобальные пременные куда больше ухудшают читабельность программы, чем пара лишних букв в обращении к переменной.
Вы всерьёз утверждаете, что
менее читабельно, чем
?
singletonInstance
менее читабельно, чем
Singleton::Instance()
?
Да. singletonInstance может быть чем угодно, какого угодно типа, уже инициализированный или еще нет. В случае с Singleton::Instance() все придельно ясно.
Это венгерская запись. Тип переменной ясен из префикса «singleton».
Про то, что можно не бояться порядка инициализации, писал выше.
Впрочем, одну деталь я упустил с самого первого примера. Глобальность переменной тоже надобно показывать префиксом. Заменяем повсюду
Про то, что можно не бояться порядка инициализации, писал выше.
Впрочем, одну деталь я упустил с самого первого примера. Глобальность переменной тоже надобно показывать префиксом. Заменяем повсюду
singletonInstance
и singletonThe
на g_singletonInstance
.Когда вызываем
…
Как видим, при ленивой инициализации порядок создания объектов так же может выйти из-под контроля и создать не меньшие проблемы, чем с глобальными объектами.
Singleton::Instance()
, мы должны опасаться, что может произойти повторный вход (reenter) в метод, из которого делаем вызов. Примерно так:A::Instance()
приводит к вызову B::Instance()
B::Instance()
приводит к вызову C::Instance()
…
X::Instance()
приводит к вызову A::Instance()
Как видим, при ленивой инициализации порядок создания объектов так же может выйти из-под контроля и создать не меньшие проблемы, чем с глобальными объектами.
По моему должно быть
static auto& instance()
static auto& instance()
про «правило двух» забыли ;)
очень люблю работать с shared_ptr на лист из shared_ptr на векторов из… ну вы поняли. У меня есть правило, если объект который я создаю будет использоваться в списках, пиши свой класс хранитель (а в внутрях если приспичит используй shared_ptr)
Правило -1: если в классе есть виртуальные методы, делайте виртуальный деструктор. И забудьте про уродливый кастомный делетер.
Жду когда примут вот этот proposal N3949 — Scoped Resource — Generic RAII Wrapper for the
Standard Library, упростит написание врапперов для ресурсов которые нужно освобождать
Standard Library, упростит написание врапперов для ресурсов которые нужно освобождать
Спасибо! Было интересно. Теперь буду знать как это называется. чтоб не просто писать и объяснять почему так, а говорить «Правило ноля.» :) Подход интересный, практичный. Единственный, как мне кажется, его изъян — это при использовании его в команде, члены команды должны о нем быть осведомлены, чтоб не выкорчевывали со словами: «Это не правильно. Надо так...». И не переписывали уже сами с использованием привил 3х или 5ти, так как они более распространены.
Почему у вас везде «хэндлер» («обработчик») а не «хэндл» («ручка»)?
Sign up to leave a comment.
«Правило ноля»