Ответ
В C++ для ограничения числа экземпляров класса обычно используют статический счетчик. Вот надежная реализация:
#include <stdexcept>
class SingletonLike {
static inline int instanceCount = 0; // Счетчик существующих объектов
static constexpr int MAX_INSTANCES = 3; // Жесткий лимит
public:
SingletonLike() {
// Проверяем лимит в конструкторе
if (instanceCount >= MAX_INSTANCES) {
throw std::runtime_error("Cannot create more than " +
std::to_string(MAX_INSTANCES) + " instances");
}
++instanceCount;
std::cout << "Instance created. Total: " << instanceCount << std::endl;
}
// Важно запретить копирование и присваивание, чтобы обойти лимит
SingletonLike(const SingletonLike&) = delete;
SingletonLike& operator=(const SingletonLike&) = delete;
// Разрешаем перемещение (перехватываем владение)
SingletonLike(SingletonLike&& other) noexcept {
// При перемещении счетчик не увеличивается
}
~SingletonLike() {
--instanceCount;
std::cout << "Instance destroyed. Total: " << instanceCount << std::endl;
}
static int getLiveInstanceCount() { return instanceCount; }
};
// Использование
int main() {
try {
SingletonLike a;
SingletonLike b;
SingletonLike c;
SingletonLike d; // Выбросит исключение
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}
Альтернативный подход — Singleton (один экземпляр):
class Singleton {
Singleton() = default; // Приватный конструктор
public:
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton& getInstance() {
static Singleton instance; // Создается один раз при первом вызове
return instance;
}
};
Важные моменты:
- Счетчик должен быть статическим — он принадлежит классу, а не объекту.
- Проверка и инкремент — в конструкторе, декремент — в деструкторе.
- Необходимо запретить копирование, иначе можно обойти лимит через
SingletonLike b = a;. - Использование
inlineдля статической переменной (C++17) избавляет от необходимости отдельного определения в .cpp файле.
Ответ 18+ 🔞
Э, слушай, вот это тема! Ну, то есть, ты хочешь, чтобы твой класс как какой-нибудь дефицитный товар был — больше трёх штук не выдавать, а то, блядь, на всех не хватит. Чистая бюрократия в коде, ёпта.
Так, смотри сюда. Главная фишка — статический счётчик. Это, типа, глобальная табличка у класса на двери, где он палочками считает, сколько его клонов уже бегает по программе. Если палочек больше трёх — всё, приехали, новых не пускаем.
Вот смотри на этот код, я его чуть поясню, а то ты, может, не въедешь.
#include <stdexcept>
class SingletonLike {
static inline int instanceCount = 0; // Вот эта палочка, считает живых
static constexpr int MAX_INSTANCES = 3; // А это лимит, его не превысить
public:
SingletonLike() {
// Заходишь в конструктор — первым делом на счётчик глянь
if (instanceCount >= MAX_INSTANCES) {
throw std::runtime_error("Cannot create more than " +
std::to_string(MAX_INSTANCES) + " instances");
}
++instanceCount; // Всё чисто — добавляй ещё одну палочку
std::cout << "Instance created. Total: " << instanceCount << std::endl;
}
// А вот это, блядь, ВАЖНЕЙШЕЕ правило! УДАЛЯЕМ копирование!
SingletonLike(const SingletonLike&) = delete;
SingletonLike& operator=(const SingletonLike&) = delete;
// Перемещение разрешаем, там счётчик не трогаем, просто право владения переходит
SingletonLike(SingletonLike&& other) noexcept {
// Пусто, потому что при перемещении новый объект не создаётся, старый умирает
}
~SingletonLike() {
--instanceCount; // Объект помер — вычёркивай палочку
std::cout << "Instance destroyed. Total: " << instanceCount << std::endl;
}
static int getLiveInstanceCount() { return instanceCount; }
};
Представляешь, что будет, если копирование оставить? Овердохуища объектов наделаешь! Написал SingletonLike b = a; — и всё, лимит ебёныш, система послана нахуй. Поэтому delete, и точка.
А теперь, чувак, главный подвох, про который все забывают! Смотри:
int main() {
try {
SingletonLike a; // 1
SingletonLike b; // 2
SingletonLike c; // 3
SingletonLike d; // А вот тут будет тебе "хиросима и нигерсраки"! Исключение вылетит!
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl; // И получишь ты в лог: "Cannot create more than 3 instances"
}
}
Всё, четвёртому пизда рулю. Конструктор ругнётся и выкинет тебя с позором.
Ну а если тебе нужен совсем уж царь-объект, один-единственный?
Тогда это классический Singleton, ёперный театр. Тут уж не три, а один, и всё.
class Singleton {
Singleton() = default; // Конструктор спрятан, с улицы не вызвать
public:
// Опять же, копирование и присваивание — под запретом
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
// А вот этот метод — единственные ворота
static Singleton& getInstance() {
static Singleton instance; // Магия! Создастся один раз при первом вызове
return instance; // И всегда будешь получать ссылку на него
}
};
Вот это, блядь, красота. Хоть сто раз вызывай getInstance() — тебе всегда один и тот же объект подсунут. Доверия ебать ноль, но зато надёжно.
Коротко по делу, чтобы в голове осело:
- Статический счётчик — это как швейцар у класса, считает, кто вошёл и вышел.
- Лимит проверяй в конструкторе — не пускай лишних.
- Удали копирование (
= delete) — это святое! Иначе какой-нибудь распиздяй обойдёт твою защиту. inlineпеременная (C++17) — удобно, не надо её в.cppфайле отдельно определять.- Деструктор не забудь — когда объект умирает, швейцар должен вычеркнуть его из списка.
Вот и вся магия. Сделаешь так — будет тебе счастье, а не код. Главное, не проёбывай пункт с удалением копирования, а то будет тебе не ограничение, а манда с ушами.