C++ статический список с приватным конструктором

Я прошу прощения, если это спросили, я не уверен, как это лучше всего сказать, и не мог найти его.

По сути, у меня есть класс, для которого я хочу сохранить карту, и этот список должен содержать единственные экземпляры объекта.

using std::unordered_map;
class MyClass
{
    ~MyClass() {};
    MyClass() {};   // these actually contain code which operate on the classes data
    static unordered_map<Uint32, MyClass> list;
public:
    static const MyClass& GetObject(Uint32 key) {return list[key];};

};

Когда я компилирую свой код, он в основном дает мне кучу ошибок из STL о том, что он вызывает удаленные функции и тому подобное, что имеет смысл, потому что unordered_map, вероятно, использует конструктор и деструктор, поэтому я объявил unordered_map другом

friend class unordered_map<Uint32, MyClass>;

Однако, похоже, ошибок не меньше, что я предполагаю из-за классов, используемых unordered_map, таких как pair и hash. Поэтому мой вопрос: есть ли альтернатива этому? Должен ли я просто объявить больше вещей, которые, по-видимому, друзья сообщают об ошибках из компилятора, или есть другой метод?

2 ответа

Решение

ОБНОВЛЕНИЕ: TC любезно указал пару вещей, которые я пропустил, так что этот ответ сделал полный оборот...

#include <iostream>
#include <unordered_map>
#include <map>
#include <cinttypes>

class MyClass
{
    typedef std::unordered_map<uint32_t, MyClass> Instances;
    friend Instances;
    friend std::pair<uint32_t, MyClass>;
    friend std::pair<const uint32_t, MyClass>;
  public:
    static const MyClass& getObject(uint32_t key) { return instances_[key] = 2 * key; }
    ~MyClass() {}
    int n() const { return n_; }
  private:
    MyClass() : n_(-1) { }
    MyClass& operator=(int n) { n_ = n; return *this; }
    int n_;
    static Instances instances_;
};

MyClass::Instances MyClass::instances_;

int main() {
    const MyClass& m20 = MyClass::getObject(20);
    const MyClass& m21 = MyClass::getObject(21);
    std::cout << m20.n() << ' ' << m21.n() << '\n';
}

Выше кода на ideone.com.

Согласно комментариям, список необходимой дружбы не задокументирован Стандартом, поэтому может порваться с новыми версиями компилятора или при портировании на другой компилятор.

В качестве альтернативы вы можете хранить (умные) указатели в unordered_map,

Так. Вы в настроении делать что-то раздражающее. Итак, давайте сделаем это. Как говорит AlexD, вам не хватает публичного деструктора. Для unordered_map необходим доступ к нему (возможно, через некоторый внутренний класс, определенный реализацией).

Итак, давайте сделаем это, и давайте сделаем то, что вы должны были сделать в первую очередь, то есть сделать намного меньший и более простой тестовый пример:

#include <unordered_map>

class MyClass {
    public:
        ~MyClass() {}

    private:
        MyClass() {}
};

int main() {
    std::unordered_map<int, MyClass> x;
    x.at(3);
    //x[3];
}

Теперь это хорошо компилируется.

Теперь обратите внимание, что я закомментировал x[3], Мы не можем использовать это. Это потому, что если 3 не существует на карте, мы бы назвали конструктор по умолчанию MyClass, который является частным. И поскольку компилятор не знает во время компиляции, правда ли это, он должен убедиться, что он может вызвать конструктор.


Из комментариев есть опасение, что вы не можете вставить какие-либо объекты в эту карту. Хорошо, давайте добавим статический метод фабрики и избавимся от этой проблемы:

#include <unordered_map>
using std::unordered_map;

class MyClass {
    public:
        static MyClass factory() { return MyClass(); }
        ~MyClass() {}

    private:
        MyClass() {}
        int x;
};

int main() {
    std::unordered_map<int, MyClass> x;
    x.insert(std::make_pair(3, MyClass::factory()));
    x.emplace(4, MyClass::factory());
}
Другие вопросы по тегам