C ++ уникальные объекты - PullRequest
2 голосов
/ 24 марта 2011

Я хотел бы создать класс, в котором возможный набор экземпляров ограничен и пользователи не могут создавать новые экземпляры.Например, валюты уникальны, и пользователи библиотеки, с которой я работаю, не должны иметь возможность создавать новые валюты или копировать существующие.Я думаю, это похоже на многотонный образец.Что у меня пока есть:

#include <string>
#include <boost/smart_ptr/shared_ptr.hpp>

struct Currency {
public:
    typedef const Currency * Pointer;

    std::string code;

    static const Currency & Get(const std::string & Code);
private:
    Currency();
    Currency(const std::string & c);
};

Currency::Currency(const std::string & c)
:code(c) {}

const Currency & Currency::Get(const std::string & Code) {
    typedef boost::shared_ptr<Currency> Value;
    typedef std::map<std::string, Value> MapType;
    static std::map<std::string, Value> map_;

    if (map_.empty()) {
        // Initialize your map here, from a database query or what have you...
    }
    MapType::const_iterator it = map_.find(Code);
    if (it == map_.end()) {
        throw std::exception(("[Currency::Get] Currency '" + Code + "' not found").c_str());
    }
    return *it->second;
}

Есть ли какие-либо очевидные проблемы с этим дизайном?(Я знаю, что это не потокобезопасно) Есть ли общепринятая техника / шаблон, о котором я не знаю, который традиционно используется для достижения этой цели?

Ответы [ 5 ]

1 голос
/ 24 марта 2011

Объявите личный конструктор копирования Currency::Currency(const Currency&), но не определяйте его. Это предотвращает инициализацию объекта Currency с другим объектом Currency. Аналогично, объявите частный оператор присваивания Currency& Currency::operator=(const Currency&). Таким образом, вы предотвращаете присвоение одной валюты другой валюте.

1 голос
/ 24 марта 2011

Просмотрите boost:noncopyable, чтобы предотвратить копирование;Это хорошее справочное решение, которому вы можете доверять и учиться.Предотвратить создание экземпляров легко: конструктор private.

0 голосов
/ 24 марта 2011

У вас уже есть все, что вам нужно!

РЕДАКТИРОВАТЬ:

Просто измените часть, где вы бросаете свое исключение:

if (it == map_.end()) {

    if ( -- part of allowed set -- ){
       -- create a new currency --
    }
    else {
       throw std::exception(("[Currency::Get] Currency '" + Code + "' not found").c_str());
    }
}

ВыМожно выполнить сравнение, чтобы увидеть, разрешена ли валюта различными способами:

  1. Другая карта с перечнем разрешенных строковых кодов
  2. Сравнение регулярных выражений по коду
  3. Проверка кода вручную по статическому массиву допустимых значений

EDIT2: Ниже приведен полностью отдельный ответ от приведенного выше:

Из описаниявашей проблемы, вы, возможно, захотите использовать перечисления, а не классы, чтобы различать возможные типы валют.

enum Currency { US, CAN, JPY, CHF, EURO };

std::map<Currency curreny, std:string code>;

РЕДАКТИРОВАТЬ 3:

Добавить что-то вроде:

private:
    std::vector<Currency> initializedList;

И в вашем методе Get вместо возврата "it-> second" вернуть ссылку на объект в векторе.Если он еще не существует, сначала поместите объект в вектор.

0 голосов
/ 24 марта 2011

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

0 голосов
/ 24 марта 2011

Я полагаю, что вы говорите о паттерне Синглтона.Так что вы можете прочитать об этом.

В большинстве языков способ получить синглтон состоит в том, чтобы

1) сделать ваши конструкторы приватными

2) создать экземпляр одного экземпляра (singleton) вашего класса внутри класса (private static)

3) создайте статический метод (class), который возвращает указатель на статический экземпляр private, созданный на шаге № 2 (обычно называемый getInstance () илиinstance () или что-то в этом роде.)

Каждый, кому нужно использовать этот синглтон, затем вызывает

MyClass foo = MyClass::getInstance();
foo.doWork( blah blah );

и использует синглтон для своей работы.

Синглтоны не являютсяпо определению (я думаю) потокобезопасен, и вы правы, заметив это.Добавление безопасности потока - отдельная проблема.

Похоже, вы прошли большую часть пути с вашим решением.

...