Об использовании C ++ синглтон-класса - PullRequest
1 голос
/ 16 февраля 2012

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

Connection.getInstance().get_input_stream();

У меня два вопроса: (1) это правильное использование синглтон-класса (2) для реализации этого, я пробовал что-то вроде этого:

class Connection {
public:
    static Connection& getInstance() {
        static Connection instance; // Guaranteed to be destroyed   
        return instance;
    }
    std::istream& get_istream() {
        return is;
    }

    void set_istream(std::istream & stream) {
            is = stream;
    }
private:
    std::istream& is;
}

Сначала этот код по какой-то причине не компилируется.Во-вторых, неудобно, что вам нужно позвонить set_istream(), прежде чем его можно будет использовать.Есть ли лучший способ сделать это?Спасибо.

РЕДАКТИРОВАТЬ: Судя по всему, пытаться назначить ссылку является моей глупостью, как многие из вас указали.Вторая часть состоит в том, как передать stream информацию в синглтон - кажется, это не стоит того, что говорит о том, что это может быть неправильным вариантом для ее использования.Спасибо всем за ответы.

Ответы [ 3 ]

3 голосов
/ 16 февраля 2012

Ссылка не может быть изменена после создания, поэтому для "установки" istream вам придется передать его в ctor:

class Connection {

    /* ... */

    Connection(std::istream & stream) : is(stream) {}
private:
    std::istream& is;
}

Однако возникает проблема того, каквы передаете правильный поток в ctor при создании статического экземпляра - и ответ на него заключается в том, что он нетривиален (в лучшем случае).Вы можете использовать указатель вместо ссылки, так что вы можете создать объект и навести его на реальный поток позже, но в этот момент вы в основном напрашиваетесь на проблемы (требующие двухэтапной инициализации).

В конце концов, это просто не стоит того.Мой совет был бы против использования синглтона в этом случае вообще.Похоже, что это добавляет довольно много работы и дает мало (если вообще что-то) взамен.

Довольно многие начинают советовать вообще не использовать singleton s, по крайней мере, в C ++, ичестно говоря, я склонен согласиться большую часть времени.Именно из-за такой ситуации у вас обычно мало что получается в обмен на работу, которую вы над этим выполняете.

1 голос
/ 16 февраля 2012

Не компилируется по двум причинам. Во-первых, у вас есть небольшая проблема с синтаксисом вызова. Исправьте это так:

Connection::getInstance().get_input_stream();

Во-вторых, вы не можете присвоить ссылку, она должна быть инициализирована во время создания. Поскольку ваш конструктор вызывается из середины getInstance, это нецелесообразно. Вместо этого используйте указатель.

Да, неудобно вызывать set_istream до того, как ваш синглтон может быть использован, но это кажется неизбежным.

1 голос
/ 16 февраля 2012

Мне всегда говорили избегать синглетонов, поэтому здесь есть две части:

class Connection {
public:
    static std::istream& getInstance() {
        assert(is);
        return *is;
    }    
    static void set_istream(std::istream & stream) {
            is = &stream;
    }
private:
    static std::istream* is;
}
std::istream* Connection::is = NULL;

int main() {
    Connection::set_istream(std::cin);
    Connection::getInstance() << "moomoomoo\n";
}

Примечание. Я сделал поток static, указатель и глобальный (так что на самом деле это одиночный код).Ваш код .... не был. Нет никакой причины иметь такое количество ссылок, и если у вас есть is = blah, где is является ссылкой, то не повторяет ссылку на .будет копировать справа налево, что для потоков, не имеет смысла и даже не скомпилируется.

Конечно, синглтоны плохие. Используйте глобальные или не синглетоны. (Это глобальный, который может быть создан только один раз)

//params are ignored after first call
template<typename... Ts>
std::istream& Connection(Ts... Us) { 
    static std::ifstream c(std::forward<Ts>(Us)...);
    return c;
}

int main() {
   //construct and use
   Connect("input.txt") << "thing" << std::endl;
   Connect() << "stuff";
   Connect("this is ignored") << "IM A COW STOP SAYING IM A DUCK";
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...