singlepost

Singleton на C++ << На главную или назад  

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

53 ответов в теме “Singleton на C++”

  1. 53
    Дмитрий Гайдамович ответил:

    >> Ну это по D 2.0 вообще-то. :) Кстати, интересный язык, рекомендую к ознакомлению.
    Ах да, ступил…

  2. 52
    Артём Шалхаков ответил:

    2 Виктор Шугаев

    > Тёма (надеюсь ты не обижаешься, что я тебя так называю)

    Не обижаюсь. Я ж не икона с надписью "Артем Аркадьич", LOL.

    > Синглтон – это прежде всего объект, а значит в одном из своих измерений данная абстракция имеет абстракцию данных, которые представляют внутреннее состояние.

    Интересное дело, что раз синглтон один, то его вполне можно реализовать с помощью функций, изменяющих _внутреннее состояние_. Не знаю, с чего ты взял, что я агитирую за исключительно чистые функции?

    // вариант нумер раз

    namespace foo {
    int s = 0;
    int mutate(int a) {
    s += a;
    return s;
    }
    }

    // вариант нумер два
    // сразу же видим очевидный оверхед по количеству буковок

    template<typename T> class Singleton {
    public:
    static T& Instance() {
    static T theSingleInstance;
    return theSingleInstance;
    }
    };

    class Foo : public Singleton<Foo> {
    public:
    Foo() : s(0) {}
    int mutate(int a) {
    s += a;
    return s;
    }
    private:
    int s;
    };

    int main(int argc, char** argv) {
    // используем
    int s = foo::mutate(5);
    int ss = Foo::Instance().mutate(5);
    }

    Первый вариант таки проще (и не требует pImpl и прочих извращений). :) В этом конкретном случае лучше будет, конечно же, все засунуть в одну функцию (как в твоем примере).

    > чтобы ты, мог яснее представить то, о чем я говорю попробуй реализовать синглтон реализующий накопитель своих вызовов на подобии того, который я приводил в терминах чистых функций. А я посмотрю, кто будет отвечать за хранение информации о количестве предыдущих вызовов.

    Эммм… Переписать-то могу:

    fun x = modify (+x) >> get

    Только вот спрятать внутреннее состояние не получится. Зато появляются другие фишки, например, безопасная многопоточность.

    > А отсутствии неявных ленивых вычислений в С++ делает состояние этого контекста вполне предсказуемым.

    Те же синглтоны позволяют отложить инициализацию, хоть и гарантируют ее. Плохо ето, мне не нравится.

  3. 51
    Артём Шалхаков ответил:

    2 Дмитрий Гайдамович

    > >>//www.digitalmars.com/d/2.0/module.html
    > Круто, спасибо! Модула-2 – любимый язык моего дипломного руководителя. Ох, и давно это было…

    Ну это по D 2.0 вообще-то. :) Кстати, интересный язык, рекомендую к ознакомлению.

  4. 50
    Константин Смотритель ответил:

    Дмитрий, я никак не пойму, что тебя смущает?! =) Читал я про Прокси, я его даже упомянул выше, что именно он тут и используется =) Более того, именно ГОФ в своё время меня и сподвиг… Что не так-то? =) Чем не нравится словосочетание "новое"? Или "автоматизация" не устраивает? =) Я же не телепат =)

    Про "новое" – я не припоминаю общеизвестное описание именно такого "авто" синглтона. Если ты знаешь, где он описывается – просвяти =) Самому хотелось бы узнать =) Заметь, что речь идёт именно о симбиозе синглтона + умного указателя, а не о чём-то из них по отдельности. Везде натыкаюсь только на синглтон Маерса. Открой мне глаза, буду знать, как такой "авто" синглтон называется. Ссылки на общеизвестные вещи типа синглтона Маерса или на умных указателей можно не приводить =)

    Народ, кто ещё знает, как приведённый мной синглтон называется и кем был описан? А то впору на RSDN идти спрашивать.

  5. 49
    Victor Shugaev ответил:

    Тёма (надеюсь ты не обижаешься, что я тебя так называю), вот тебе конструктивизм:

    Нельзя противопоставлять синглтону нэймспэйс+функции.
    Это как сравнивать ужа с ежом.

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

    Функции (а тем более чистые функции) – это алгоритмическая абстракция и с её помощью абстрагировать представление данных по меньшей мере не логично.

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

    чтобы ты, мог яснее представить то, о чем я говорю попробуй реализовать синглтон реализующий накопитель своих вызовов на подобии того, который я приводил в терминах чистых функций. А я посмотрю, кто будет отвечать за хранение информации о количестве предыдущих вызовов.

    >Функция с побочными эффектами вполне себе может попросить ввод у пользователя.

    Я долго программирую на функциональных языках и прекрасно осознаю, что такое функции без побочных эффектов. И всегда принимаю во внимание контекст. А отсутствии неявных ленивых вычислений в С++ делает состояние этого контекста вполне предсказуемым.

  6. 48
    Дмитрий Гайдамович ответил:

    Константин, вв главной книжке про "костыли к ООП" GoF в разделе "Применимость" для паттера Proxу читаем:

    – умная» ссылка – это замена обычного указателя. Она позволяет выполнить дополнительные действия при доступе к объекту. К типичным применениям такой ссылки можно отнести:

    - подсчет числа ссылок на реальный объект, с тем чтобы занимаемую им память можно было освободить автоматически, когда не останется ни однойссылки (такие ссылки называют еще «умными» указателями [Ede92]);
    - загрузку объекта в память при первом обращении к нему;

    Перевод 2001 г, оригинал 1995 г

  7. 47
    Дмитрий Гайдамович ответил:

    Тогда я не понимаю, почему это ново. Ну ладно, не суть.

  8. 46
    Константин Смотритель ответил:

    Конечн =)

  9. 45
    Дмитрий Гайдамович ответил:

    >> Новое тут в АВТОМАТИЗАЦИИ механизма подсчёта
    Под автоматизацией ты имеешь в виду AddRef в конструкторе, Release в деструкторе CSingle и создание по первому обращению?

  10. 44
    Константин Смотритель ответил:

    Хех, Дмитрий, я же говорю, что тут ничего нового – стандартный паттерн =)Новое тут в АВТОМАТИЗАЦИИ механизма подсчёта. Кстати, на мой взгляд, правильнее сказать что "он есть в boost" =) Ну да ладно.

    По поводу макроса – я бы не стал рисковать ради экономии единственной строки =( А то щас точно Артёмы набегут =)

  11. 43
    Дмитрий Гайдамович ответил:

    2 Константин Смотритель

    >> Дмитрий, а если сделать ход конём:
    Да, это напрашивается. Так конечно лучше. И сделать макрос для определения классов, подобных CObj, чтоб не забывать писать friend.

    >> … а именно переход к автоматическому подсчёту ссылок, отказ от вызовов Instance/AddRef/Release …
    Ну smart pointer для reference counting. В ATL пример такого подхода есть.

    Спасибо за упоминание Модулы, я знаю :)

    2 Артём Шалхаков

    >> //pascal.proweb.kz/index.php?page=43
    Turbo Pascal и Borland Pascal – это то, с чего я начинал. Причина, по которой я с ними расстался, достаточно глупая: мне не нравилось писать begin-end.

    >>//www.digitalmars.com/d/2.0/module.html
    Круто, спасибо! Модула-2 – любимый язык моего дипломного руководителя. Ох, и давно это было…

    >> Потому что классы — для ООП, а модули — для модульности.
    Ну да, я понимаю, ты воспринимаешь классы только как инструмент для абстракции данных. Но из них же можно и модули делать, и очень хорошо получается, уверяю.

    >> pImpl, думаешь, от хорошей жизни, что ли?
    Что есть pImpl?

  12. 42
    Артём Шалхаков ответил:

    2 Виктор Шугаев

    > Эта статья не рассматривает описываемую технику, как технику для работы с AST!!!

    Ошибся, сорри. Алсо, спасибо за развернутый ответ, не знал этих деталей. Тем не менее, поработать с AST вполне можно в D (ну и Lisp, etc.).

    > Даже когда она себя ведёт не так, как нам бы хотелось, её поведение всё равно детерминировано, просто для функций с побочными эффектами поведение определяется не только аргументами, но и контекстом.

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

    Функция с побочными эффектами вполне себе может попросить ввод у пользователя.

    > твой "изначальный пойнт" был о бреде мозга, пораженного терминальной стадией ООП.

    Не перевирай. :) Толсто.

    Алсо, конструктивных возражений по теме (singleton vs namespace+функции) от тебя так и не поступило.

    > Так вот, похоже, что у тебя терминальная стадия ФП.

    Я тебя обидел штоле, или это весна+обострение? Ты тут для чего — для обсуждения или для перехода на личности? Пиши в личку.

  13. 41
    Victor Shugaev ответил:

    Интересная статья, только никакого отношения к АSТ не имеет.

    Автор строит шаблонную абстракцию основанную на рекурсивной композиции и обладающую свойством замыкания.

    Эта статья не рассматривает описываемую технику, как технику для работы с AST!!!
    Всё то, что в этой статье можно считать работой сАST в конечном счёте сводится к идиоме об отложенных вычислениях и предположению, что компилятор развернёт в генерируемом коде(функции evaluate()) inline operator() и все его вложенные вызовы (т.к. обстракция рекурсивная) а этой гарантии ни стандарт ни известные мне реализации компиляторов дать не могут.
    К тому же если в подвыражении нет объекта класса DExpr<> то это подвыражение будет вычислено и его дерево не будет передано в шаблон.
    Ещё к тому же все функции и операторы, используемые в этих выражениях должны быть перегружены для работы с объектами класса DExpr<>. Так, что нет ни какой возможности разработать абстракцию, которая будет разбирать деревья для произвольных функций. Т.к. мы должны заранее перегрузить все возможные функции, которые могут использоваться в выражении.

    да будет тебе известно, любая функция (не только чистая) имеет детерминированное поведение если выполняются предусловия её вызова. Даже когда она себя ведёт не так, как нам бы хотелось, её поведение всё равно детерминировано, просто для функций с побочными эффектами поведение определяется не только аргументами, но и контекстом. Но это никак не лишает её детерминированности. Поэтому не возможно создать генератор случайных чисел, используя лишь систему команд без источника энтропии…Учи мат. часть.

    твой "изначальный пойнт" был о бреде мозга, пораженного терминальной стадией ООП.

    Так вот, похоже, что у тебя терминальная стадия ФП.

  14. 40
    Константин Смотритель ответил:

    Дмитрий, ключевое решение в CSingle – это не подсчёт ссылок, а именно переход к автоматическому подсчёту ссылок, отказ от вызовов Instance/AddRef/Release . Это сильно облегчает жизнь, при этом становится очевидным, что при правильном подходе динамические объекты (new/delete) проигрывают статическим (объявленым как член-переменные). Это я хотел показать, т.к. просто подсчёт ссылок есть в любом синглтоне =)

  15. 39
    Константин Смотритель ответил:

    Артём, "И все-таки. Сколько будет 2 * 2? Всегда 4." мда, учи теорию. Могу порекомендовать Карпов Ю.Г. "Теория автоматов". Там всё про состояния и конечные автоматы =) И вообще, чем машина Тьюринга хуже лямбда-исчисления? На всякий случай напомню, что они эквивалентны.

    "Прошу заметить, что синглтон тут не нужен. Нужен модуль." – прошу заметить, что в этом случае у тебя ТОЛЬКО синглтоны и получаются. Не чуешь проблем? ;-)

    "чтобы управлять ресурсами (которых мало" – я имел в виду варианты использования чего-то вместо инкапсуляции… Тебе, если уж ты ориентируешься на Хаскель-подобия, можно было вспомнить замыкания. То есть я хотел получить ответ, со списокм механизмов, умеющих данные "сворачивать и разворачивать", как инкапсуляция в ООП (и в меньшей мере наследование). Ну ладно, забили.

  16. 38
    Константин Смотритель ответил:

    Дмитрий, Модула-2 по сути тот же Паскаль. За несущественными отличиями =)

  17. 37
    Константин Смотритель ответил:

    Артём, а вообще, я чёт не понял, о чём спорим-то? О_о А то воды разлилось уже на 2 страницы =) Синглтон вроде есть, если я не ошибся (что Дмитрий проверит) – то задача решена, ответ дан… Что тебе не нравится в предложенном решении? Хочешь поговорить о модулях/преимуществах ФЯ – действительно, как советуют, заведи тему (можновХоливарах).

    Потому как странно в ответ на просьбу подсказать реализацию С++ объекта, который можно создать только раз, отвечать "Синглтон это бред мозга, пораженного терминальной стадией ООП. " Ты, конечно, крут, но надо держать себя в руках ;-)

  18. 36
    Константин Смотритель ответил:

    Дмитрий, а если сделать ход конём: конструктор у CObj объявлен private, а класс CSingle у него в друзьях. Теперь невозможно создать CObj ВНЕ CSingle<>. Дополнительно бывает полезно написать:
    typedef CSingle<CObj> CSingleObj;

    При этом условия задачи уже выполняются без оговорок, приведённых мной ранее. Что скажешь? ;-) Теперь не придётся читать инструкцию"? =)

    (Код отредактирован)

  19. 35
    Артём Шалхаков ответил:

    2 Виктор Шугаев

    > Должен тебя расстроить, шаблоны С++ НЕ работают с абстрактными синтаксическими деревьями.

    //ubiety.uwaterloo.ca/~tveldhui/papers/Expressi...

    Довольно жуткий способ закодировать AST в типы.

    > использования арифметики, не означает использование функциональной парадигмы. Её начали использовать ещё до того, как такой термин возник.

    Кто говорил о функциональщине? Я говорил о *детерминизме* чистых функций (когда поступил вопрос, что же плохого в синглтонах в частности и вычислениях с мутирующим внутренним состоянием вообще). По счастливой случайности, арифметические операции детерминированы (вычисления с плавающей точкой не рассматриваем).

    > Поэтому ты самостоятельно обдумай лишний раз при чём здесь функции и namespaces, когда задача стояла об объектах и классах.

    Внимательно таки прочитай мой изначальный пойнт.

  20. 34
    Victor Shugaev ответил:

    Тёма,

    Иногда лучше молчать чем говорить. А в твоём случае лучше продолжать учёбу и не спорить о тех вещах которые не знаешь.

    Должен тебя расстроить,шаблоны С++ НЕ работают с абстрактными синтаксическими деревьями. Работа с шаблонами больше похожа на препроцессор, чем на компилятор.

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

    Простой пример накопителя (арифметика без функциональщины)
    int accamulate (int rhs)
    {
    static int sum = 0;
    return sum+=rhs;
    }

    отличный ответ: "Потому что некоторые вещи лучше оставить на самостоятельное обдумывание." Поэтому ты самостоятельно обдумай лишний раз при чём здесь функции и namespaces, когда задача стояла об объектах и классах.

  21. 33
    Артём Шалхаков ответил:

    2 Дмитрий Гайдамович

    > Артем, ты какие имеешь в виду модули, как в Паскале, или как Руби?

    Как в Паскале, родимом. :)

    //pascal.proweb.kz/index.php?page=43 ("секция инициализации") Вот помню, что там и про деинициализацию тоже где-то было, но не могу найти. :(

    > Про Модулу-2 и D имею только теоретические знания.

    //www.digitalmars.com/d/2.0/module.html ("Static Construction and Destruction")

    > И почему ты отказываешь классам в этом священном праве, называться модулями?

    Потому что классы — для ООП, а модули — для модульности. ;) (Это, конечно же, не значит, что ООП не обеспечивает кой-какую модульность.)

    > У них все равно может быть интерфейс и информационная закрытость, прикинь, да?

    pImpl, думаешь, от хорошей жизни, что ли? (читай: информационной закрытости в них нет)

    2 Виктор Шугаев

    > Тёма, почему ты отвечаешь только на некоторые вопросы?

    Потому что некоторые вещи лучше оставить на самостоятельное обдумывание.

    > Потому, что когда человек пытается навязать использование функциональной парадигмы в языке, который эту самую парадигму не поддерживает

    Где навязывание? Я как раз сразу же предложил пространства имен и функции. Почитай мои комменты внимательнее. Зато когда спросили об альтернативах, то я сразу же отметил, что для Си++ не знаю, зато мне известны для Haskell.

    > Ты о них заговорил для того, чтобы показать свою псевдоинтеллектуальность???

    Осиль предыдущий абзац и отправляйся на лечение. :)

    > Почему бы тогда не обсудить то, как реализовать операции квазицитирования и раскавычивания, как универсальные средства метапрограммирования в С++???

    Потому что в Си++ операции с AST можно производить разве что через expression templates, и это очень неблагодарное занятие. ;)

    > Это не функциональный язык, и никакой ощутимой!!! выгоды от использования чистых функций здесь нет.

    Ну как же. Арифметикой вон пользуются и не жалуются лишний раз.

    > Здесь нет гарантированного разворачивания хвостовых рекурсий, нет неявного распараллеливания вычислений.

    Неявного распареллеливания вычислений нет и в Haskell (это я о concurrency), более того, ленивость не сильно располагает к этому.

  22. 32
    Юрий Лисичкин ответил:

    >> И все-таки. Сколько будет 2 * 2? Всегда 4. А сколько будет
    >> myubersingleton::getInstance()->multBy(4)? Никто не знает (и не узнает,
    >> пока не запустит этот код).
    И это прекрасно… и называется это полиморфизм %))

  23. 31
    Victor Shugaev ответил:

    Тёма, почему ты отвечаешь только на некоторые вопросы? Будь добр, ответь на все.

    А я тебе еще раз предложу полечиться! Потому, что когда человек пытается навязать использование функциональной парадигмы в языке, который эту самую парадигму не поддерживает – либо выё..ся, либо больной, в любом случае это не имеет никакого отношения ни к программированию, ни к решаемой задаче.

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

    Почему бы тогда не обсудить то, как реализовать операции квазицитирования и раскавычивания, как универсальные средства метапрограммирования в С++???

    Это не функциональный язык, и никакой ощутимой!!! выгоды от использования чистых функций здесь нет. Здесь нет гарантированного разворачивания хвостовых рекурсий, нет неявного распараллеливания вычислений. И если ты нашёл серебрянную пулю (а это верный признак, что ты недоучка так, как не видишь других решений ) для Haskell, это совсем не значит, что это решение оптимальное для других языков.

  24. 30
    Дмитрий Гайдамович ответил:

    2 Артём Шалхаков

    >> Вы часто забиваете гвозди отверткой? Только честно! :)
    Я иногда делаю это многофункциональным инструментом. Отвертка – такая вещь, обычно их нужно штук пять иметь, и все равно, будешь только что-нибудь завинчивать.

    >> У меня возникает ощущение, что я разговариваю с человеком, который
    не программировал на языке с поддержкой модулей.
    Артем, ты какие имеешь в виду модули, как в Паскале, или как Руби? Про Модулу-2 и D имею только теоретические знания. И почему ты отказываешь классам в этом священном праве, называться модулями? Только потому что они могут гнездиться по сто штук на файл, и наоборот, быть "размазанными" по сотне файлов? У них все равно может быть интерфейс и информационная закрытость, прикинь, да?

    2 Андрей Петров

    >> Очередной Холивар корпоративных программистов против научников :-\
    Ааааааа!!!! Меня посчитали! А где тут "холи", я че-т не пойму? Я абсолютно не фанат какой-то одной идеи, языка или конструкции. Я искренне пытаюсь понять Артема, и почему он считает, что синглтон – это бред. Собственно, можно дальше и не продолжать, поскольку тут и так все понятно: каждый основывается на своем опыте и представлениях об удобном. Надеюсь, до настоящего бреда ни у кого пока не доходит на этом поприще.

  25. 29
    Владимир Белов ответил:

    Андрей Петров +5)))))))

  26. 28
    Андрей Петров ответил:

    Очередной Холивар корпоративных программистов против научников :-\

  27. 27
    Артём Шалхаков ответил:

    2 Дмитрий Гайдамович

    > Это что, аксиома? И что, если я сделаю то же при помощи класса, а не модуля или namespace – это бред?

    Вы часто забиваете гвозди отверткой? Только честно! :)

    > Конечно, класс более "всевмещающая" концепция, классом можно и модуль изобразить, и namespace

    Можно, но в результате получится "синглтон", который есть верх безобразия.

    > Ну приблизительно в той же мере, в какой паттерн "дом" (фундамент-стены-кровля) намекает на ограничения, вызванные свойствами самих стройматериалов и является "костылем", потому что кирпичики сами не складываются в коттедж.

    У меня возникает ощущение, что я разговариваю с человеком, который не программировал на языке с поддержкой модулей.

  28. 26
    Артём Шалхаков ответил:

    2 Константин Смотритель

    > Синглтон "возвращает число" оперируя своим внутренним состоянием, ради хранения которого (и упрпавления которым) он и создан.

    И все-таки. Сколько будет 2 * 2? Всегда 4. А сколько будет myubersingleton::getInstance()->multBy(4)? Никто не знает (и не узнает, пока не запустит этот код).

    > Твой пример функций+неймспейсов не содержит никаких данных.

    Я подумал, что достаточно просто вывести остальное. Обыкновенный Си-стайл: внутри файла-модуля определяются статичные глобальные переменные, а пользователю предоставляются функции, которыми он будет оперировать.

    Прошу заметить, что синглтон тут не нужен. Нужен модуль.

    > Также на вопрос "варианты" требуется ответ. Меня не интересует оценка средней температуры по больнице, меня интересуют твои взгляды и знания. Будь так добр.

    Не для Си++: чтобы управлять ресурсами (которых мало, типа file handles, db connections, etc.), можно использовать регионы (monadic regions, что-то вроде RAII, но более общее решение); в случае, когда вычислению требуется контекст (окружение: например, все переменные в области видимости), можно воспользоваться монадами (они позволяют "перетаскивать" это самое окружение, не напрягая мозг). Ну и так далее. Решений много.

    2 Виктор Шугаев

    > алсо твой подход тождественен известному паттерну (костылю) "monostate"…

    Где-то я говорил о каких-то monostate?

    > Если ты решил, поднять своё ЧСВ over 9000, рассказывая нам – дебилам программирующим на С++ с использованием ООП, о преимуществах функциональной парадигмы, то тебе не сюда, а к психиатору.

    Звездец. Пытаешься людей сподвигнуть на хоть какое-то шевеление мозгами, а тут на тебе: "чувак, иди лечись".

  29. 25
    Дмитрий Гайдамович ответил:

    2 Константин Смотритель

    "Программные скобки CSingle<>" -это обычный такой smart pointer для разделяемого объекта с reference counting, это полезная методика, но она не предотвращает нецелевого использования CObj, тебе придется расширить твою инструкцию по пользованию твоим template-ом, и её регулярно будут забывать читать. А возможность создания единственного объекта – это способ спроектировать сам класс таким образом, чтобы определить политику его использования.

  30. 24
    Дмитрий Гайдамович ответил:

    2 Артём Шалхаков

    >> Задачи singleton [1] решаются с помощью системы модулей… :) ) Это что, аксиома? И что, если я сделаю то же при помощи класса, а не модуля или namespace – это бред?Пардон, но я ещё помню время, когда namespacе-ы не поддерживались весьма уважаемыми компиляторами. Конечно, класс более "всевмещающая" концепция, классом можно и модуль изобразить, и namespace, и эта чрезмерная гибкость как раз и накладывает дополнительные требования по аккуратности программирования, за что многие С++ и не любят.

    >> Использовать классы там, где нужны модули — бред. Ну, в прынцыпе, в C++ по-другому нельзя.
    Ну вот, договорились. По другому как бредить на С++ нельзя? Конструктивненько… Хотя, писать хорошо на "плюсах" действительно непросто.

    >>С другой стороны, любой паттерн явно намекает на ограничения языка. Является костылем, то бишь.
    Ну приблизительно в той же мере, в какой паттерн "дом" (фундамент-стены-кровля) намекает на ограничения, вызванные свойствами самих стройматериалов и является "костылем", потому что кирпичики сами не складываются в коттедж.

    >> Это та же самая глобальная переменная. :)
    Не совсем. Здесь присутствуют те самые init() и shutdown() – это конструктор и деструктор, единая точка доступа к ресурсу.

    >>PS алсо, как ни странно, от глобальных переменных все хотят избавиться…
    Ну синглтон как раз и нужен для тех мест, где от них не избавиться. Если хотите, это ОО-wrapper для глобальной переменной.

    PS. Я не фанат С++, он мне не очень нравится, просто тут такая задача.

  31. 23
    Константин Смотритель ответил:

    Артём, "использовать классы там, где нужны модули — бред. Ну, в прынцыпе, в C++ по-другому нельзя." Тогда это уже не бред, а особенность данного конкретного языка. Который, заметим, позволяет реализовывать синглтон бес введения специфических понятий наподобие "модуль".

    "С другой стороны, любой паттерн явно намекает на ограничения языка. Является костылем, то бишь."
    В общем виде паттерн – это в том числе и синтаксис языка. Любая программа – это паттерн решения данной конкретной задачи. По твоим словам, выходит, всё программирование – это костыль. Пессимистично ;-)

  32. 22
    Константин Смотритель ответил:

    Артём, серьёзные различия, как правило, скрыты в мелочах… "небольшое синтаксическое удобство" вполне может быть главным козырем. Тем более, что это удобство видится большим: речь не шла о передаче явного this, ты меня не так понял. Явная или неявная передача this приводит к ООП: не станешь же ты использовать структуры в стиле Модулы (Си) =) Речь шла о передаче каждый раз всего требуемого набора переменных (или, что хуже, использования глобальных). Хороший пример – код РНР без классов. Как тебе оно? Удобно? =) Вот эта особенность (инкапсуляция, я как раз о ней) и говорит в пользу ООП. Хочешь обсудить недостатки структур в стиле Модулы? – велкам =)

    Теперь про "недетерминированность". Я просил не дать мне ещё одно определение проблемы, а указать на суть проблемы использования синглтона. Иначе у нас получается демагогия. С моей точки зрения тут как раз нет никакой недетерминированности – ни по времени жизни, ни по состоянию (а оно обязательно есть, иначе не нужен синглтон) синглтона. Синглтон "возвращает число" оперируя своим внутренним состоянием, ради хранения которого (и упрпавления которым) он и создан. Итак, будет с твоей стороны вторая попытка объяснения проблемы использования синглтона? =)

    Также на вопрос "варианты" требуется ответ. Меня не интересует оценка средней температуры по больнице, меня интересуют твои взгляды и знания. Будь так добр.

    Твой пример функций+неймспейсов не содержит никаких данных. Реальный чёрный ящик (программа) оперирует данными. Дополни пример данными, иначе он ничего не значит =(

  33. 21
    Victor Shugaev ответил:

    Артём, лечи мозг…
    потом еще раз читай задачу :)

    если ты адепт академической функциональщины – программируй на Haskell…

    алсо твой подход тождественен известному паттерну (костылю) "monostate"…

    только к чему ты его здесь привёл не ясно? Когда в условии задачи тебе русским языком сказано, что нужно создавать объект класса. Где у тебя здесь класс, где его объекты – не совсем понятно.

    Если ты решил, поднять своё ЧСВ over 9000, рассказывая нам – дебилам программирующим на С++ с использованием ООП, о преимуществах функциональной парадигмы, то тебе не сюда, а к психиатору.

    моар алсо, Я так и не понял в чём проблема с синглтоном мейерса (закрытый конструктор, статическая функция instance() возвращающая ссылку на локальный статический объект), он не меняет внешний контекст, он изменяет состояние, инкапсулированое в объект этого синглтона, который по семантике является неявным параметром этой функции…

  34. 20
    Константин Смотритель ответил:

    Дмитрий, "Только для данной задачи, мне кажется, это не решение. По условию задачи, мы должны создать класс, экземпляр которого можно создать лишь однократно. Объект какого класса здесь можно создать в единственном экземпляре? Я такого не вижу."

    А смысл повторять то, что я уже сказал? О_о Ещё один пост? ;-)
    Плюс я указал в примере, какой именно класс будет создан единственный раз: любой класс, объявленый с использованием программных скобок в виде шаблона CSingle<> . Чем не решение задачи? Лучше бы подискутировал на эту тему =) Т.е. чем программные скобки CSingle<> отличаются от возможности создания единственного объекта =)))

  35. 19
    Артём Шалхаков ответил:

    2 Константин Смотритель

    > В чём сложность отладки, можно поподробнее? =)

    В недетерминированности.

    Мне вот интересно, как бы Вы относились к арифметике, если бы 5 + 4 могло, в зависимости от погоды на одной из населенных планет Туманности Андромеды, вернуть как 9, так и любое другое число? :)

    > С кучей функций есть проблема – придётся в каждую функцию передавать скопище переменных, вместо неявного this.

    Явный this тоже вполне можно передать. :) Впрочем, к синглтону это никоим образом не относится.

    > Одно это говорит однозначно в пользу ООП

    Что именно? Небольшое синтаксическое удобство что ли? %)

    > Варианты?

    Много их, правда, не в Си++.

    > Приведи пример использования функций+неймспейсов.

    namespace foo {

    void init() { … }
    void shutdown() { … }

    }
    :)

  36. 18
    Артём Шалхаков ответил:

    2 Дмитрий Гайдамович

    > Только не очень понял, singleton – это как раз "применять ООП не по назначению" что ли?

    Да, именно.

    > Где тут бред мозга?

    Задачи singleton [1] решаются с помощью системы модулей (примеры: Pascal, D). В Си++ модулей нет, зато есть пространства имен. Не совсем равноценная, но все-таки замена (для этой конкретной задачи).

    Использовать классы там, где нужны модули — бред. Ну, в прынцыпе, в C++ по-другому нельзя.

    > Он ведь паттерн, то есть удачный пример использования ООП.

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

    > Основанный на опыте. Мой опыт подтверждает то же самое. В чем же все же сложность и ненадежность singleton-а? И что там собственно отлаживать? По поводу порядка инициализации static-ов – это как сделаешь.

    В неявном состоянии. Это та же самая глобальная переменная. :)

    PS алсо, как ни странно, от глобальных переменных все хотят избавиться, а вот от неуправляемых побочных эффектов — нет, хотя именно они являются корнем проблемы.

    [1] инициализация/деинициализация, единственная точка доступа к ресурсу

  37. 17
    Константин Смотритель ответил:

    Артём, "порядок инициализации определяется во время работы программы" – а чем труднее отлаживать?! В приведённом выше примере порядок инициализации определяется графом инкапсуляции. В чём сложность отладки, можно поподробнее? =)

    С кучей функций есть проблема – придётся в каждую функцию передавать скопище переменных, вместо неявного this. Одно это говорит однозначно в пользу ООП; либо нужна близкая концепция – т.е. наличие инкапсуляции как таковой пожалуй что обязательно… Иначе будет тратится лишнее время программиста =) Варианты? Приведи пример использования функций+неймспейсов.

  38. 16
    Дмитрий Гайдамович ответил:

    2 Артём Шалхаков

    > Бгг, не надо вот гнать на ООП. И не надо применять его не по назначению…
    Я и не гоню. Только не очень понял, singleton – это как раз "применять ООП не по назначению" что ли? Где тут бред мозга? Он ведь паттерн, то есть удачный пример использования ООП. Основанный на опыте. Мой опыт подтверждает то же самое. В чем же все же сложность и ненадежность singleton-а? И что там собственно отлаживать? По поводу порядка инициализации static-ов – это как сделаешь. На С++ легко сделать и так и так.

    > Передать их преподу as-is. ;) Пущай присоединяется к дискуссии…
    Даже если вообразить наличие в природе препода, усомнившегося в целесообразности книжного паттерна, все равно придется как-то объяснить ему, что именно имеется в виду: в чем назначение ООП, почему синглтон не соответствует назначению ООП etc, спорные, в общем-то вещи.

  39. 15
    Артём Шалхаков ответил:

    2 Петр Рогов
    > и хранить кучу глобальных переменных, да?

    Разумеется, нет. Вы про абстракцию слышали когда-нибудь?

    > а отлаживать DEBUG'ом?

    А чем же еще? Кстати, синглтоны отлаживать будет труднее, потому что порядок инициализации определяется во время работы программы, а не во время компиляции.

    2 Дмитрий Гайдамович

    > Я думаю, Артём, в группе про холивары с Вами с радостью и поспорят и согласятся, обсудят простоту и надежность обыкновенных процедур, и насколько ООП поражает мозг.

    Бгг, не надо вот гнать на ООП. И не надо применять его не по назначению. Я только об этом, если Вы не заметили.

    > А девушке наверно задание дали, что же ей прикажете сказать преподавателю, услышав Ваши саркастические слова?

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

  40. 14
    Дмитрий Гайдамович ответил:

    Схема с подвешенным объектом с refcnt понятная, её можно с успехом применять, например, для организации безопасной ссылки (той, которая отслеживает, жив ли объект "под ней"). Только для данной задачи, мне кажется, это не решение. По условию задачи, мы должны создать класс, экземпляр которого можно создать лишь однократно. Объект какого класса здесь можно создать в единственном экземпляре? Я такого не вижу.

  41. 13
    Константин Смотритель ответил:

    Рабята, обратите внимание: задача не просто "сделать синглтон", а сделать класс, "объект которого можно создать только в одном экземпляре". Это немного сложнее, чем стандартный синглтон. Моя идея заключается в том, что в отличие от обычного синглтона, имеется прокси-класс, который создаётся сколь угодно раз, но наш "базовый" класс при этом создаётся единственный раз. Хотя, допускаю, более простое решение задачи описано в литературе, но оно и более кривое (например, генерация исключения при создании более одного объекта). Хотя, может, Надежде такой вариант и нужен?… В любом случае, привожу свою мысль в удобочитаемом виде:

    /* Файл Single.h
    Класс не допускает наследование.
    Нежелательно динамическое размещение (assert'ы как раз из-за этого =).
    Создаётся только один экземпляр CBase.
    Не требует инстанциирования шаблона.
    Не поддерживает многопточность.
    CBase должен иметь конструктор без параметров.
    */
    template <class CBase>
    class CSingle
    {
    public:
    CSingle() : pcache(single.instance()) {}

    CBase* operator ->()
    {
    return pcache;
    }

    ~CSingle() { single.release(); }
    private:
    CBase* pcache;

    template<CBase>
    class CSingleImpl // Введён для упрощения инстанциирования
    {
    public:
    CSingleImpl() : pn(0),px(0) {}

    CBase* instance()
    {
    if(!pn) px=new CBase();
    pn++;
    }

    void release()
    {
    assert(pn>=0);// Поможет отловить утечки
    pn–;
    if(!pn) delete px;
    }

    ~CSingleImpl() {assert(!pn);} // Поможет отловить утечки
    private:
    int pn;
    CBase* px;
    };

    typedef CSingleImpl<CBase> tSingle;
    static tSingle single;
    };

    template CSingle<CBase>::tSingle single;

    // Обновление после 06.03.2009 – пример использования
    /* Объект класса CObj можно создать единственный раз
    */
    class CObj
    {

    private:
    friend class CSingle<CObj>;
    CObj() {…} // Единственный закрытый конструктор

    };

    typedef CSingle<CObj> CSingleObj;

  42. 12
    Константин Смотритель ответил:

    Использование очень удобное (удобнее обычного синглтона). Динамическое инстанциирование крайне не приветствуется: тогда преимущества теряются.

    Пример:

    class A
    {
    CSingle<CObj> obj;

    obj->…
    };

    class B
    {
    CSingle<CObj> obj;

    obj->…
    };

    - здесь нет надобности в вызовах Instance/AddRef/Release и им подобных, время жизни CObj строго зависит от совокупного времени жизни A и B. При этом объект класса CObj невозможно создать более одного раза, используя шаблон CSingle.

  43. 11
    Константин Смотритель ответил:

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

    Комменты?

  44. 10
    Юрий Лисичкин ответил:

    а вобще имхо аккаунт фейковый=)

  45. 9
    Евгений Гаврин ответил:

    // //lurkmore.ru/Луговский

    Юрий: Вот про паттерны вопрос сложный – ее надо на примере осваивать и пользовать по началу в качестве настольного мануала. Иначе с наскоку ее читать бесполезно.

  46. 8
    Петр Рогов ответил:

    To Артем Шалхаков: и хранить кучу глобальных переменных, да? а отлаживать DEBUG'ом? да и вообще писать можно на ассемблере, а что, зато быстро и эффективно. и, главное, круто как!

  47. 7
    Дмитрий Гайдамович ответил:

    Есть даже такой отдельный жанр статей про программирование: объяснять, почему синглтон – это зло, бред, болезнь и т. д. Я думаю, Артём, в группепро холивары с Вами с радостью и поспорят и согласятся, обсудят простоту и надежность обыкновенных процедур, и насколько ООП поражает мозг. А девушке наверно задание дали, что же ей прикажете сказать преподавателю, услышав Ваши саркастические слова? Понимаете, зараза ООП настолько распространилась по планете, что Голливуду впору снимать очередную кассовую антиутопию. В главной роли – Виталий Луговский. Есть другие кандидатуры?

  48. 6
    Артём Шалхаков ответил:

    Синглтон это бред мозга, пораженного терминальной стадией ООП. Гораздо проще и надежнее использовать пространства имен и обыкновенные процедуры.

  49. 5
    Алексей Близнюк ответил:

    Вот один из вариантов:
    //rus.captureit.ru/Articles/GlobalObjects.html

  50. 4
    Владимир Плешаков ответил:

    Другие книжки курить не стоит?))) Я пару раз затягивался Ватсоном – неплохо так…

  51. 3
    Юрий Лисичкин ответил:

    кури книжку "приемы объектно-ориентированного проектирования. паттерны проектирования" для начала %)

  52. 2
    Надежда Муранец ответил:

    Благодарю, попробую разобраться. :)

  53. 1
    Дмитрий Гайдамович ответил:

    приватный конструктор и паблик getInstance(), который возвращает ссылку на локальный статик
    (смотри также паттерн singleton)

Клуб программистов работает уже ой-ой-ой сколько, а если поточнее, то с 2007 года.