Как ограничить количество объектов класса в C++

«Как ограничить количество объектов класса в C++» — вопрос из категории ООП, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В 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;
    }
};

Важные моменты:

  1. Счетчик должен быть статическим — он принадлежит классу, а не объекту.
  2. Проверка и инкремент — в конструкторе, декремент — в деструкторе.
  3. Необходимо запретить копирование, иначе можно обойти лимит через SingletonLike b = a;.
  4. Использование inline для статической переменной (C++17) избавляет от необходимости отдельного определения в .cpp файле.