LINUX.ORG.RU

Изучаю Boost::singleton

 ,


0

2

Доброго времени суток!

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

Пробовал вот так (не копая глубоко в исходники буста):

#include <boost/serialization/singleton.hpp>
#include <iostream>
using namespace std;
using namespace boost::serialization;

template <class T> class TServer :
    public singleton<TServer<T>>
{
private:
    int a;
    T b;
public:
    TServer(int s) : a(s){
        cout<<"TServer"<<endl;
    }
    int geta(){return a;};
    int getb(){return b;};
    void setb(const T & c){b=c;};
};

int main(int argc, char**argv)
{
    TServer<int> fg(15);
    fg.setb(-5);
    cout<<fg.geta()<<endl;
    TServer<int> fg2(25);
    cout<<fg.getb()<<endl;
    cout<<fg2.getb()<<endl;
    cout<<fg.geta()<<endl;
    cout<<fg2.geta()<<endl;
    TServer<int> *fg3=new TServer<int>(105);
    cout<<fg.geta()<<endl;
    cout<<fg2.geta()<<endl;
    cout<<fg3->geta()<<endl;
    return 0;
}

Вывод:

TServer
15
TServer
-5
0
15
25
TServer
15
25
105

То есть создаются три разных экземпляра класса.

★★

Синглтон - это те же самые глобальные переменные, только в красивом фантике. Ты абсолютно уверен, что оно тебе надо?

Gvidon ★★★★
()
Ответ на: комментарий от Gvidon

не абсолютно.

если есть решение, которое сработает на этапе компиляции, то оно будет предпочтительнее решения, которое сработает на этапе выполнения.

aido ★★
() автор топика
Ответ на: комментарий от aido

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

Gvidon ★★★★
()

Изучаю Boost::singleton

Никому не интересно.

Oxdeadbeef ★★★
()
Ответ на: комментарий от Gvidon

Хочется написать класс для демона. Без классов демоны пишутся как два пальца об асфальт, а вот с ними че-то туплю. Причины? Причина одна: нет смысла создавать в одном приложении два и более экземпляров класса-демона. + Удобно просто отнаследоваться от демонизирующего класса и больше о всех тонкостях не вспоминать. То же самое относится и к классам, которые будут демонизированы: нет, например, смысла создавать два и более экземпляров класса для слежения за периферией компа, или для сервера математических расчетов (хочется просто запустить его в бэкграунде и время от времени проверять результат выполнения задачи).

aido ★★
() автор топика
Ответ на: комментарий от aido

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

aido ★★
() автор топика
Ответ на: комментарий от aido

как запретить второй раз дернуть конструктор?

Ну вот, приехали... Ты бы теорию немного подтянул сначала, чтоли. Если коротко, то все конструкторы и ссылка/указатель на инстанс прячутся в private, а в public выкладывается обычная функция getInstance. Но это по простому, а в крестах есть ещё много тонкостей, как всё это делается, да тут ещё и буст, там в доках написано, какой интерфейс нужно реализовать.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)

Если есть возможность не делать синглетон — не делай.

Deleted
()
Ответ на: комментарий от no-such-file

хорошо, а как этим пользоваться, создавать экземпляр класса?

В смысле, так чтоль?


class OnlyOne
{
public:
        static const OnlyOne& Instance(int a,double b,char c)
        {
                static OnlyOne theSingleInstance(a,b,c);
                return theSingleInstance;
        }
private:        
        OnlyOne(){}
        OnlyOne(int a,double b,char c):a1(a),b1(b),c1(c){}
        OnlyOne(const OnlyOne& root);
        int a1;
        double b1;
        char c1;
        OnlyOne& operator=(const OnlyOne&);
};

int main(int argc,char**argv)
{
OnlyOne one=OnlyOne::Instance(1,2.0,'f');
return 0;
}
Как-то все равно ломает мозг такой код...

aido ★★
() автор топика
Ответ на: комментарий от aido

А если я еще добавлю строчку

OnlyOne two=OnlyOne::Instance(2,3.0,'e');
То внутренние переменные a,b,c переопределятся или вылезет ошибка, что, мол, второй раз собираюсь вызвать конструктор класса в том же экземпляре?

aido ★★
() автор топика
Ответ на: комментарий от aido

Можешь не страдать ерундой, а сделать getInstance() без параметров. Когда ты что-то хочешь внутри поменять — вызывай методы явно. Естественно, тебе придётся их написать.

Заодно про статические переменные тоже неплохо бы почитать.

Deleted
()
#include <boost/serialization/singleton.hpp>
#include <iostream>
using namespace std;
using namespace boost::serialization;

template <class T> class TServer :
    public singleton<TServer<T>>
{
private:
    int a;
    T b;
public:
    TServer() {
        // http://www.boost.org/doc/libs/1_48_0/libs/serialization/doc/singleton.html#requirements
        // In order to be used as singleton<T> , the type T must be default constructable.
        cout<<"TServer"<<endl;
    }
    int geta(){return a;};
    int getb(){return b;};
    void seta(int c) {a=c;}
    void setb(const T & c){b=c;};
};

TServer<int> &i() { return TServer<int>::get_mutable_instance(); }

int main(int argc, char**argv)
{
    i().seta(15);
    i().setb(-5);
    cout<<i().geta()<<endl;
    i().seta(25);
    cout<<i().getb()<<endl;
    cout<<i().getb()<<endl;
    cout<<i().geta()<<endl;
    cout<<i().geta()<<endl;
    i().seta(105);
    cout<<i().geta()<<endl;
    cout<<i().geta()<<endl;
    cout<<i().geta()<<endl;
    return 0;
}

Вывод:

TServer
15
-5
-5
25
25
105
105
105

i-rinat ★★★★★
()
Последнее исправление: i-rinat (всего исправлений: 1)
Ответ на: комментарий от i-rinat

This manipulator may be used to produce a line of output immediately, e.g. when displaying output from a long-running process, logging activity of multiple threads or logging activity of a program that may crash unexpectedly. An explicit flush of std::cout is also necessary before a call to std::system, if the spawned process performs any screen I/O. In most other usual interactive I/O scenarios, std::endl is redundant when used with std::cout because any input from std::cin, output to std::cerr, or program termination forces a call to std::cout.flush(). Use of std::endl in place of '\n', encouraged by some sources, may significantly degrade output performance.

In many implementations, standard output is line-buffered, and writing '\n' causes a flush anyway, unless std::cout.sync_with_stdio(false) was executed. In those situations, unnecessary endl only degrades the performance of file output, not standard output.

http://en.cppreference.com/w/cpp/io/manip/endl

Deleted
()

Что бы не создавалось больше одного экземпляра класса, (ВНЕЗАПНО) не создавай больше одного экземпляра класса и задокументируй.

anonymous
()

Вместо синглтона тогда уж лучше применить паттерн Dependency Injection, и пусть DI-контейнер и хранит в себе эти инстансы.

static_lab ★★★★★
()
Ответ на: комментарий от anonymous

Аноним, так хочется, чтоб компилер выдавал предупреждение вида «ты-му**к, раз решил создать два таких класса»

aido ★★
() автор топика
Ответ на: комментарий от aido

тогда глобальная переменная. скажет, правда, не компилятор, а компоновщик.

anonymous
()
Ответ на: комментарий от aido

Логично-то логично, но как запретить второй раз дернуть конструктор?

Как-то так:

static SingleClass* obj = nullptr;
if(obj == nullptr)
{
   obj = new SingleClass();
}
return obj;
А вообще почитайте про синглтон. Там полторы с половиной строки текста.

andreyu ★★★★★
()

Уже наверное сказали, что не нужно этим пользоваться.

anonymous
()

нахер тебе всрался этот буст? ты шо не можешь в статик варибл?

anonymous
()

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

Legioner ★★★★★
()
Ответ на: комментарий от andreyu

Понятие «ленивый синглтон» вам о чем говорит?

Нет такого понятия. Есть понятия lazy evaluation и lazy initialization. А то, что у тебя - просто потоконебезопасное говно, нарушающее все принципы безопасного доступа к памяти в C++, включая корректное уничтожение.

asaw ★★★★★
()
Ответ на: комментарий от asaw

включая корректное уничтожение.

К слову, иногда можно так и делать. Если на все время работы программы нужен глобальный кеш, а тратить время на его «корректное уничтожение» при завершении не имеет смысла.

anonymous
()
Ответ на: комментарий от anonymous

А потом нормальные люди вынуждены копаться в дырявом коде таких вот сумрачных гениев и выяснять где это действительно можно было не делать, а где «гений» просто облажался. Бесят подобные программы, на которые какой-нибудь valgrind совершенно справедливо ругается про утечки (и «гении» об этом даже знают, но гордо оставляют свой говнокод в таком виде - они же «лучше знают»).

Не может быть оправдания некорректному коду. «Тратить время на его «корректное уничтожение» при завершении не имеет смысла» - просто детский лепет. Если ты такой умный, то тебе ничего не должно помешать уничтожить всё корректно за минимальное время.

asaw ★★★★★
()
Последнее исправление: asaw (всего исправлений: 1)
Ответ на: комментарий от asaw

«Тратить время на его «корректное уничтожение» при завершении не имеет смысла» - просто детский лепет. Если ты такой умный, то тебе ничего не должно помешать уничтожить всё корректно за минимальное время.

Детский лепет это твои обезьяньи повадки. Обезьянке рассказали как надо делать и почему, она послушно исполняет в своем загончике. А если ты посмотришь код нормальных программистов, чьими программами пользуется весь мир, то там и не такое бывает. Взять тот же busybox из недавних новостей, там даже файлы руками не всегда закрываются.

anonymous
()
Ответ на: комментарий от anonymous

Мои «повадки», как ты выразился, основаны исключительно на опыте командной разработки ПО. И этот опыт говорит, что в шею надо гнать сумрачных гениев, которые думают о том, сколько тактов займет то или иное выражение вместо того, чтобы думать о корректности и о том, как их код потом будут развивать другие.

А если ты посмотришь код нормальных программистов

Не надо мне эту лапшу на уши вешать. После этих «нормальных программистов» пишут тома литературы о том, как не нужно делать в C++. И уже даже дозрели до того, чтобы сделать профили в компиляторах, в которых подобный выпендреж будет запрещен.

Взять тот же busybox из недавних новостей, там даже файлы руками не всегда закрываются.

Чтобы не закрывать руками файлы в C++ есть RAII. А кривой код есть кривой код.

asaw ★★★★★
()
Ответ на: комментарий от asaw

Мои «повадки», как ты выразился, основаны исключительно на опыте командной разработки ПО

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

Не надо мне эту лапшу на уши вешать. После этих «нормальных программистов» пишут тома литературы о том, как не нужно делать в C++.

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

А кривой код есть кривой код.

Только понятие «кривой код» у каждого свое. Если ты своими замашками полезешь в ядро Linux, например, и начнешь рассказывать как у них криво написан код, то на тебя выльют тонны говна, если вообще обратят внимание.

anonymous
()
Ответ на: комментарий от anonymous

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

asaw ★★★★★
()
Последнее исправление: asaw (всего исправлений: 1)
Ответ на: комментарий от asaw

Нет такого понятия. Есть понятия lazy evaluation и lazy initialization.

И его реализацию я привел в качестве примера.

А то, что у тебя - просто потоконебезопасное говно, нарушающее все принципы безопасного доступа к памяти в C++, включая корректное уничтожение.

Все пытаюсь понять, причем тут я и что вы пытаетесь мне доказать?

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

Все пытаюсь понять, причем тут я и что вы пытаетесь мне доказать?

Я тебе уже всё написал. Если ты не понял - перечитай. И по ссылке сходи наконец.

asaw ★★★★★
()

Конструктор должен быть приватным

LongLiveUbuntu ★★★★★
()
Ответ на: комментарий от asaw

Сишник детектед.

Нет.

Я тебе не мешаю писать на твоём Си в стиле камикадзе, но какого буя ты в Си++ с этим говном лезешь и всех поучаешь?

А зачем ты пишешь на С++, если тебе не бывает нужен «стиль камикадзе»? Чтоб читать тонны литературы как не надо делать? Есть же другие языки, где все гораздо проще и безопасней.

anonymous
()
Ответ на: комментарий от anonymous

А зачем ты пишешь на С++, если тебе не бывает нужен «стиль камикадзе»? Чтоб читать тонны литературы как не надо делать? Есть же другие языки, где все гораздо проще и безопасней.

Потому что опасные фишки Си++ бывают нужны в тысячных долях процента кода, выполняющего 20% вычислений, да и то не всегда. Но Си++, в отличие от других языков, не заставляет платить за то, чем ты не пользуешься. И даже безопасный код на Си++ получается в разы быстрее т.н. «безопасных» языков.

asaw ★★★★★
()
Ответ на: комментарий от asaw

Зачем ты врешь? Есть более быстрые и безопасные окамлы и русты. Да и даже не так быстро, зато надежно и ноги не отстрелить и разрабатывать в разы быстрее.

anonymous
()
Ответ на: комментарий от anonymous

более быстрые и безопасные окамлы и русты.

Ага, расскажи нам ещё сказок в стиле вот этой вот школоты: Опубликованы C++ Core Guidelines (комментарий).

asaw ★★★★★
()
Последнее исправление: asaw (всего исправлений: 1)
Ответ на: комментарий от asaw

И что не так? Мс нужно было наплодить хомячков для системы, они внедрили кресты повсеместно. Все верно он заметил. Было и есть много более надежных и отличных инструментов, но хомячки кодят на крестах, потому что «виндовс_же_на_них_написана!» и «весь_геймдев_же_кресты_!»

anonymous
()
Ответ на: комментарий от anonymous

Пиши на «более надежных и отличных инструментах». Как напишешь что-нибудь нужное - расскажешь.

asaw ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.