Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 06.09.2014, 07:06   #1
rrrFer
Санитар
Старожил
 
Аватар для rrrFer
 
Регистрация: 04.10.2008
Сообщений: 2,577
По умолчанию

Здравствуйте. У GoF для шаблона Singleton написано, что конкретно для языка С++ будет проблема в случае если синглетоны зависят друг от друга по причине того, что САБЖ не регламентирован по стандарту.

Собственно, я вроде бы представляю себе проблему, но не понимаю как она к синглетону относится. Ведь порядок вызова конструкторов будет полностью определяется порядком вызова статических функций-членов instance(). Разве нет?

И вот ведь в случае

Код:
static Foo::bar() {
  static Foo foo;
}
Объект foo будет создан только при вызове функции. О чем пишет GoF?

Переместите тему в общие вопросы С++ ?

From Stilet: Готово.

Последний раз редактировалось Stilet; 06.09.2014 в 10:36.
rrrFer вне форума Ответить с цитированием
Старый 06.09.2014, 10:41   #2
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Я лично не в курсе таких дебрей, потому... сумимасен, короче
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 06.09.2014, 13:16   #3
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,331
По умолчанию

Речь идет о глобальных переменных - порядок вызова их конструкторов не определен.

Кстати, статичные переменные внутри функции могут быть граблями при многопоточном использовании.
waleri вне форума Ответить с цитированием
Старый 06.09.2014, 14:04   #4
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

rrrFer

Вкратце суть:
Если ваша программа с завидным постоянством падает при завершении - вы утратили контроль за сложностью вашего проекта. Или может быть просто не умеете сингелтоны.

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


Проблема инициализации:

Код:
struct some
{
   // порядок инициализации единиц трансляций не определен
   // поэтому, на готовность sSingelton рассчитывать нельзя
   // до запуска функции main
   static singelton sSingelton;
};
нет никаких гарантий, что сингелтон1 уже готов к работе, когда он понадобился при инициализации сингелтону2

Либо для сингелтонов с ручным приводом:

Код:
            static TypePtr GetInctance()
            {
                assert(msInstance);
                return msInstance;
            }
причины те же, что и выше, с той поправкой: пользователь вручную может и должен пасти очередность создания и удаления сингелтонов, что бы синглетон1 при создании мог безопасно пользоваться сингелтон2.

На мой взгляд: оба варианта в топку.

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

Код:
struct Singelton
{
   // больше не зависит от порядка инициализации единиц трансляций
   static Singelton& Get() { static Singelton s; return s;}
};
При первом же вызове функции, локальный статик обязан проинициализироваться.

Время жизни и очередность созданияуничтожения:

Если в конструкторе сингелтон1 вызвать сингелтон2, то возникнет следующая ситуация:

На время работы конструктора сингелтон1, его как объекта ещё не существует.
Но поскольку он уже позвал сингелтон2, то получается, что сингелтон2 гарантированно был создан раньше, а значит проживет дольше:


Код:
singelton1::singelton1() //<--- ещё только строится, а значит ещё пока не существует
{
    singelton2::Get(); //уже построился.
}
сингелтон2 будет гарантированно создан раньше, чем сингелтон1
А значит, гарантированно проживет дольше,чем сингелтон1
А значит, сингелтон1, который позвал другой сингелтон в своем конструкторе, теперь имеет возможность совершенно безопасно его эксплуатировать на всем времени своей жизни.

Созависимость сингелтонов:

Рассмотрим код:

singelton1.h
Код:
#pragma once

struct singelton1
{
    singelton1(); 
    ~singelton1();
    static singelton1& Get();
};
singelton1.cpp
Код:
#include <iostream>
using namespace std;


#include "singelton2.h"
#include "singelton1.h"

singelton1::singelton1() 
{
    singelton2::Get();
    cout<<"singelton1: ctor\n"; 
}
singelton1::~singelton1() { cout<<"singelton1: dtor\n"; }

singelton1& singelton1::Get() { static singelton1 s; return s; }
singelton2.h
Код:
#pragma once

struct singelton2
{
    singelton2(); 
    ~singelton2();
    static singelton2& Get();
};
singelton2.cpp
Код:
#include <iostream>
using namespace std;


#include "singelton2.h"
#include "singelton1.h"

singelton2::singelton2() 
{
    singelton1::Get();
    cout<<"singelton2: ctor\n"; 
}
singelton2::~singelton2() { cout<<"singelton2: dtor\n"; }

singelton2& singelton2::Get() { static singelton2 s; return s; }
Здесь мы видим: сингелтон1 в конструкторе пытается использовать сингелтон2, а сингелтон2 - сингелтон1.

Каким же тогда получится порядок инициализации и время жизни этих сингелтонов?

Ответ: unspecified behavior
Зависит от того, какой сингелтон: первый или второй позвали первым.
Если первым позвали singelton1, значит первым построится singelton2, и наоборот.

Код:
#include "singelton1.h"
#include "singelton2.h"

int main(int argc, char* argv[])
{
    (void)argc;(void)argv;

    singelton2::Get();
    singelton1::Get();

    //singelton1: ctor
    //singelton2: ctor
    //singelton2: dtor
    //singelton1: dtor
}
или так:

Код:
#include "singelton1.h"
#include "singelton2.h"

int main(int argc, char* argv[])
{
    (void)argc;(void)argv;

    singelton1::Get();
    singelton2::Get();
    

    //singelton2: ctor
    //singelton1: ctor
    //singelton1: dtor
    //singelton2: dtor
}
Суть unspecified behavior в том, что в случае созависимостей, кто бы ни был создан первым - это будет "правильный первый".
То бишь, независимо от причуд вызывающей стороны, порядок создания и время жизни сингелтонов будет определено так, что бы все отработало без ошибок.

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

Последний раз редактировалось _Bers; 06.09.2014 в 14:12.
_Bers вне форума Ответить с цитированием
Старый 06.09.2014, 14:08   #5
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от waleri Посмотреть сообщение
статичные переменные внутри функции могут быть граблями при многопоточном использовании.
с++11 гарантирует многопоточную защиту инициализации локальной статической переменной.

Раньше за этим нужно было следить вручную.
_Bers вне форума Ответить с цитированием
Старый 06.09.2014, 14:23   #6
rrrFer
Санитар
Старожил
 
Аватар для rrrFer
 
Регистрация: 04.10.2008
Сообщений: 2,577
По умолчанию

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

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

У них такой вариант вроде бы был:
Код:
struct Singleton {
  static Singleton* instance() {
    if (0 == inst)
      inst = new Singleton;
    retuirn inst;
  }
  static Singleton *inst;
};

Singleton::inst = 0;
Тоже самое прочитал на хабре и на insidecpp (http://insidecpp.ru/patterns/singleton).

На insidecpp говорят что при отложенной инициализации (как в примере выше) проблемы нет, но у синглетона Меерса она есть:
Цитата:
Синглтон Меерса. Синглтон инициализируется в конструкторе, уничтожается в деструкторе и кроме того, сам синглтон является статическим объектом. В данном случае проблема всего одна — стандарт ничего не говорит о порядке конструирования статических объектов из разных единиц компиляции. Если у вас будет несколько сингтонов, использующих друг друга, то скорее всего этот метод приведет к проблемам.
Но насколько я понимаю, Маерс предлагал использовать локальную. статическую переменную и проблемы там нет (вы тоже об этом пишите):
Цитата:
А во-вторых, и это самое главное: нет ни одной причины делать вручную, если за вас тоже самое может сделать умная автоматика:
КОроче, проблема будет если я напишу что-то такое:

Код:
Singleton {
  static inst {
    return inst;
  }
  static Singleton inst;
}
Ну схематично...

Спасибо. Про взаимозависимости написали здорово, хотя ИМХО без кода, на пальцах оно МБ было бы более наглядно

Последний раз редактировалось rrrFer; 06.09.2014 в 14:25.
rrrFer вне форума Ответить с цитированием
Старый 06.09.2014, 14:34   #7
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от rrrFer Посмотреть сообщение

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

У них такой вариант вроде бы был:
Код:
struct Singleton {
  static Singleton* instance() {
    if (0 == inst)
      inst = new Singleton;
    retuirn inst;
  }
  static Singleton *inst;
};

Singleton::inst = 0;
Однако, приведенный выше код - это недоручной-недостатический привод. Такие обычно новички ваяют, которые ещё не знают толком языка.

Может быть банда просто не осилила плюсы?



Цитата:
Сообщение от rrrFer Посмотреть сообщение
На insidecpp говорят что при отложенной инициализации (как в примере выше) проблемы нет, но у синглетона Меерса она есть:
Но насколько я понимаю, Маерс предлагал использовать локальную. статическую переменную и проблемы там нет (вы тоже об этом пишите):
Если Маерс использовал локальный статик - значит, проблем у него нет.
Тогда это значит, что проблемы есть у insidecpp.
А если они имели ввиду именно "как в примере выше" - у них точно проблема. Проблема с языком, которого они не понимают.


Цитата:
Сообщение от rrrFer Посмотреть сообщение
КОроче, проблема будет если я напишу что-то такое:
Да.

Последний раз редактировалось _Bers; 06.09.2014 в 14:36.
_Bers вне форума Ответить с цитированием
Старый 06.09.2014, 17:21   #8
rrrFer
Санитар
Старожил
 
Аватар для rrrFer
 
Регистрация: 04.10.2008
Сообщений: 2,577
По умолчанию

Цитата:
Может быть банда просто не осилила плюсы?
Я не вчитывался в старые стандарты, но подозреваю, что может быть раньше (в старых стандартах, которые юзала банда) конструкторы локальных статических объектов вызывались при старте программы, а не при запуске функции. Тогда такая проблема могла проявляться. Ну птамушто подозрительно про это написано прям везде.

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

Кстати, навоял статью по теме: http://pro-prof.com/archives/1546 (еще вчера), но вот тема зависимостей между синглтонами (когда нужен определенный порядок инициализации) там оказалась не раскрыта... (вы тут описали лучше xD).

Последний раз редактировалось rrrFer; 06.09.2014 в 17:23.
rrrFer вне форума Ответить с цитированием
Старый 06.09.2014, 17:34   #9
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от rrrFer Посмотреть сообщение
Я не вчитывался в старые стандарты, но подозреваю, что может быть раньше (в старых стандартах, которые юзала банда) конструкторы локальных статических объектов вызывались при старте программы, а не при запуске функции. Тогда такая проблема могла проявляться. Ну птамушто подозрительно про это написано прям везде.
Стандарт не причем.
Не знаю насчет "прям везде", потому что "прям везде" я таких деццких поделий не встречал.

Встречал, например у Александресску описание разных моделей. В том числе - Феникс (умеет подохнуть когда вы ему скажите. Но если следом опять позовёте - он автоматом опять поднимется).

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

Цитата:
Сообщение от rrrFer Посмотреть сообщение
Так-то да, но у него есть преимущества отложенной инициализации (если вызова не произойдет, то и конструктор не будет вызван, а если там как-той большой и сложный объект...).
У него нет никаких преимуществ по сравнению с локальными статиками.

Локальная статическая переменная инициализируется при первом запуске функции-хозяина.

Если вы её не позовете - конструктор локального статика так же вызван не будет.

Цитата:
Сообщение от rrrFer Посмотреть сообщение
Ну и еще есть возможность освободить память в любой момент. Я лично не видел случае когда синглетон нужен временно, но допускаю что это может быть ))
Это действительно может быть нужно. Ведь говнокод случается.

Хорошая новость в том, что техника "феникс" не противоречит технике "локальный статик".

Одно другому не мешает.
_Bers вне форума Ответить с цитированием
Старый 06.09.2014, 19:07   #10
rrrFer
Санитар
Старожил
 
Аватар для rrrFer
 
Регистрация: 04.10.2008
Сообщений: 2,577
По умолчанию

Цитата:
Встречал, например у Александресску описание разных моделей. В том числе - Феникс (умеет подохнуть когда вы ему скажите. Но если следом опять позовёте - он автоматом опять поднимется).
Спасибо, прочитаю.
rrrFer вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Переход границы через курсор мышки Акоб Паскаль, Turbo Pascal, PascalABC.NET 8 26.11.2011 16:19
Порядок вызова процедуры artem611 Помощь студентам 3 11.05.2011 18:28
Получить границы диапазона через InputBox kipish_lp Microsoft Office Excel 4 18.08.2010 14:14
Порядок рисования объектов ? HWork Gamedev - cоздание игр: Unity, OpenGL, DirectX 1 13.03.2010 07:47
Z-порядок расположения объектов. Alex Cones Мультимедиа в Delphi 1 19.04.2009 14:08