Одноэлементный класс в C++

Я использовал singleton calss в следующем примере:

одноэлементный класс

Но я получаю сообщение об ошибке "Неразрешенные внешние символы".

это код, который я пробовал:

#include<iostream>
using namespace std;

class singleton
{
    int value;
    static singleton *instance;
protected:
    singleton()
    {
        value=0;
    }
public:
    static void initialize()
    {
        if(instance==NULL)
            singleton();
        else
            cout<<"An instance of singleton already exist...";
    }
    static singleton& getInstance()
    { 
        return *instance; 
    }
    int getValue() 
    { 
        return value; 
    }

};

void main()
{
    singleton::initialize();
}

Небольшое пояснение по классам Singleton было бы действительно здорово. Используемый сценарий. преимущества и недостатки. Альтернативы Синглтону. и т. д.


person Rohit Vipin Mathews    schedule 18.01.2012    source источник
comment
К сожалению, вы последовали за плохим ответом. Хоть повезло.   -  person Matthieu M.    schedule 18.01.2012
comment
Вот несколько лучших ответов   -  person Mike Seymour    schedule 18.01.2012
comment
@ Матье М: что ты предлагаешь?   -  person Rohit Vipin Mathews    schedule 03.02.2012
comment
@ Майк Сеймур: да, я прочитал ссылку. Благодарность   -  person Rohit Vipin Mathews    schedule 03.02.2012
comment
я хотел бы, чтобы кто-нибудь опубликовал хороший одноэлементный класс в качестве примера   -  person Rohit Vipin Mathews    schedule 24.02.2012
comment
Возможный дубликат шаблона проектирования C++ Singleton   -  person Trevor Boyd Smith    schedule 04.09.2018


Ответы (3)


Для начала думаю:

singleton();

должно быть:

instance = new singleton();

В вашем случае вы фактически не сохраняете только что созданный экземпляр объекта, поэтому instance всегда будет иметь значение null.

Также хорошим тоном является явная установка статики с помощью:

singleton *singleton::instance = 0;

(вне определения класса).

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

#include <iostream>

class singleton {
    protected:
        static singleton *instance;
        singleton() { }
    public:
        static singleton *getInstance() {
            if (instance == 0)
                instance = new singleton();
            return instance;
        }
};
singleton *singleton::instance = 0;

int main() {
    singleton *s1 = singleton::getInstance();
    singleton *s2 = singleton::getInstance();
    std::cout << s1 << '\n';
    std::cout << s2 << '\n';
    return 0;
}

Вы можете видеть, что оба указателя одинаковы из вывода:

0xbc0358
0xbc0358

Или эталонная версия, поскольку это то, к чему вы стремитесь:

#include <iostream>

class singleton {
    protected:
        static singleton *instance;
        singleton() { }
    public:
        static singleton& getInstance() {
            if (instance == 0)
                instance = new singleton();
            return *instance;
        }
};
singleton *singleton::instance = 0;

int main() {
    singleton &s1 = singleton::getInstance();
    singleton &s2 = singleton::getInstance();
    std::cout << &s1 << '\n';
    std::cout << &s2 << '\n';
    return 0;
}
person paxdiablo    schedule 18.01.2012
comment
О да, для начала это было хорошо, но даже при том, что он не реализовал действительно хороший класс singleton - person Rohit Vipin Mathews; 24.02.2012

В вашем файле определения вам нужно определение instance:

singleton* singleton::instance = NULL;

Вы должны отделить свое определение от своего объявления, если хотите использовать синглтон в нескольких единицах перевода.

Кроме того, как это обычно делается, нет метода инициализации:

static singleton* getInstance()
{ 
    if(instance==NULL)
        instance = new singleton();
    return instance;
}

На SO ведется много дискуссий о том, хороши или плохи синглтоны, но все согласны с тем, что их следует избегать. Вы также должны проверить их.

person Luchian Grigore    schedule 18.01.2012
comment
Это может быть общий консенсус в SO (хотя я не уверен в этом --- я думаю, что это просто случай, когда противники более громкие), но это, конечно, не в целом. Одноэлементный шаблон широко используется, и там, где это уместно, в нем нет ничего плохого. - person James Kanze; 18.01.2012
comment
@JamesKanze: Ну вот, опять... :) Широко используется не значит используется по праву. Это просто означает, что многие заблуждающиеся люди используют синглтоны, когда им это действительно не нужно. Мы не говорим, что это не будет работать, но мы говорим, что вы тратите усилия на плохой дизайн. - person GManNickG; 18.01.2012
comment
Так что действительно опасно использовать singleton в многопоточных средах? - person Rohit Vipin Mathews; 18.01.2012
comment
@GMan Но это просто ты так говоришь. Нет никаких реальных доказательств, и есть большое количество компетентных программистов, которые без проблем делают вам синглтоны. В целом, существует что угодно, но только не консенсус в отношении того, что синглтоны представляют собой плохой дизайн; на самом деле, есть очень близкие к единому мнению, что они подходят в определенных ситуациях. (Теперь, если ваш аргумент заключается только в том, что ими можно злоупотреблять или что они часто используются не по назначению, то же самое можно сказать и о многих других методах C++. Начиная с шаблонов.) - person James Kanze; 18.01.2012
comment
@CodingMastero Синглтон является общим для всех потоков, поэтому необходимо принять некоторые меры предосторожности. Как и любой объект, совместно используемый более чем одним потоком. Учитывая, что это широко известный и хорошо изученный паттерн, вероятно, проще правильно использовать синглтоны, чем другие общие объекты (но во многих случаях еще проще полностью избежать совместного использования объектов). - person James Kanze; 18.01.2012
comment
Я думаю, что консенсус направлен на то, что вам редко нужен синглтон. Большинство программистов используют их, когда они на самом деле не нужны. И использовать их, не зная подводных камней, так же плохо. - person Luchian Grigore; 18.01.2012
comment
Явная функция инициализации позволяет вам убедиться, что она инициализирована до того, как несколько потоков могут получить доступ - ваша инициализация не является потокобезопасной (а также дает утечку памяти). Одиночками (и вообще глобальными объектами) на удивление сложно безопасно управлять в C++, что является еще одной причиной избегать их. - person Mike Seymour; 18.01.2012
comment
@JamesKanze: Что должно быть одноэлементным, а не глобальным? - person GManNickG; 19.01.2012
comment
@mike, я сомневаюсь в необходимости метода инициализации exolicit, когда все, что вам нужно сделать, это вызвать get instance из основного потока, прежде чем запускать любые другие потоки. - person paxdiablo; 19.01.2012
comment
@LuchianGrigore Наверное, в этом что-то есть. Одиночка — это форма глобальной переменной, и, как правило, глобальные переменные, вероятно, используются слишком часто. Но это верно для ряда вещей. Обычно следуя моде - синглтоны были модой какое-то время, в результате чего их использовали независимо от того, подходили они или нет. То же самое можно сказать об умных указателях и шаблонах сегодня. Когда я впервые начал использовать C++, это было наследование. Во всех случаях полезна базовая техника. При правильном использовании, а не систематическом. - person James Kanze; 19.01.2012
comment
@paxdiablo: при таком подходе средство доступа не может утверждать, что оно было безопасно инициализировано; если вы забудете, то единственным признаком будут случайные, невоспроизводимые ошибки. Если вы собираетесь использовать что-то столь же подверженное ошибкам, как глобальный объект (независимо от того, украшаете ли вы его странным узором или нет), стоит сделать его максимально безопасным для использования. - person Mike Seymour; 19.01.2012
comment
@JamesKanze: Может быть, я просто следую моде, когда настаиваю на том, что зависимости должны быть явными, интерфейсы должны быть отделены от реализаций, а компоненты должны быть слабо связаны и тестироваться изолированно; но я определенно обнаружил, что эти вещи облегчают управление большими проектами и что глобальные переменные (замаскированные или нет) работают против них. Я никогда не сталкивался с прецедентом использования глобальной переменной, которую нельзя было бы лучше удовлетворить с помощью переменной с разумной областью действия, передаваемой по ссылке тому, что в ней нуждается; и я потратил больше времени, чем хотелось бы, на исправление ненужных, плохо реализованных синглетонов. - person Mike Seymour; 19.01.2012
comment
@MikeSeymour При правильном использовании синглтоны уменьшают связанность. Существенно. Это настоящая причина их использования. Что касается неофициальных свидетельств того, что я видел неправильное использование или плохо реализованные синглтоны... если я отвергну все, что я видел, что было неправильно использовано или плохо реализовано, мне не осталось бы ничего, что можно было бы использовать. - person James Kanze; 19.01.2012
comment
Спасибо за всю помощь, ребята!! Atlast я сделал потокобезопасный одноэлементный класс (надеюсь на это)!! - person Rohit Vipin Mathews; 01.02.2012

Вам нужно определить статическую переменную-член instance. Где-нибудь в глобальной области (например, между классом и функцией main) добавьте следующую строку:

singleton *singleton::instance = 0;  // use 'nullptr' if your compiler support it

Также вы можете поместить инициализацию экземпляра в getInstance:

static singleton& getInstance()
{
    if (instance == 0)
        instance = new singleton;
    return *instance;
}

и удалите функцию initialize.

Вы также можете сделать конструктор закрытым, а не защищенным, а также иметь закрытый конструктор копирования и функции присваивания для предотвращения копирования и присваивания.

person Some programmer dude    schedule 18.01.2012