LINUX.ORG.RU

Почему статической ф-ии разрешено вызывать конструктор?

 ,


1

1

Есть такой паттерн синглетон

class Singleton
{
public:
   static Singleton* Instance();
protected:
   Singleton();
private:
   static Singleton* _instance;
}
//.cpp
Singleton* Singleton::_instance = 0;
Singleton* Singleton::Instance() {
  if(_instance == 0){
     _instance = new Singleton;
  }
  return _instance;
}

И сказано, что статические ф-ии не могут обращаться к нестатическим методам класса, так вот почему статической ф-ии getInstance вдруг разрешено вызывать приватный конструктор? Ведь специально закрытым сделали, а тут лезет static. Как так?



Последнее исправление: maxcom (всего исправлений: 2)

Ответ на: комментарий от annulen

Дык и без френда можно влезть в приватные поля, да и если константа сложный тип - наверное ее тоже можно поменять, было бы дури достаточно…

Но если без угли хаков, то наверное для константного синглтона френды это косяк?

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

std::map<std::string, std::string> // ключ:значение

имена параметров конфиге совпадают с именами полей в классах и есть макрос который умеет выдернуть параметр любого типа из map и задать значение одноименного поля. На тот момент это казалось хорошей идеей - надо было быстро че то сделать что бы работало.

Конфиг всегда единственный на весь процесс. Теперь этот map гуляет по всему коду как переходящее знамя, каждый из него достает че ему надо. Накладные расходы небольшие, но это оскорбляет моей чувство прекрасного. Хочется уже сделать структуру для конфига (и наверное во тут нужен read-only синглтон), но тогда придется дублировать параметры - писать их в эту структуру, потом что бы классы оттуда выдергивали то что надо, как то геморно выглядит…

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

А можно еще кастануть обычный метод к функции принимающей первым аргументов указатель на объект;-)

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

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

если новые объекты регулярно инициализируется в процессе работы - вполне есть.

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

ты можешь реализовать глухую защиту доступа к объекту.

«Можно придумать защиту от дурака, но только от неизобретательного»(c) ;-)

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

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

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

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

если новые объекты регулярно инициализируется в процессе работы - вполне есть.

Обычно динамика подразумевает динамический же конфиг. Никто не пишет СУБД или веб-сервер, например, который нужно перестартовать, чтоб поменять настройку.

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

«Можно придумать защиту от дурака, но только от неизобретательного»(c) ;-)

защита от дурака в 99.9 процентах случаев защищает систему от некорректного поведения. про взломщиков отдельная песня

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

Почему перестартовывать? Нужно что то сделать, для этого нужно создать новый объект, это объект нужно проинициализировать…

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

Почему перестартовывать? Нужно что то сделать, для этого нужно создать новый объект, это объект нужно проинициализировать…

Ну его же кто-то создает, значит можно просто дать указатель на родителя с его настройками. Или просто на настройки.

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

Но есть нюанс - глобальную константу никто никогда не может изменить после инициализации. А у синглтона могут быть френды.

Напрашивается цитата из старины Херба :) А еще внезапным шаблоном метода можно сделать что угодно или всемогущим reinterpret_cast'ом, только надо или понимать чего делаешь, или да, бензопилы детям не игрушка — но и на проекте где применяются бензопилы им делать нечего — вдруг порежутся.

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

Да хрен ты что от достаточно настойчивого плюсовика спрячешь. При желании можно и в .data-сегмент ручонками залезть :)

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

Ок, следите за руками:

// a.hpp
class A{ ... };
A* get_A();
// a.cpp
static A* pa = 0;
A* get_A(){
   if(!pa) pa = new A;
   return pa;
}

здесь кто то может сам сделать экземпляр A() - если ему не сказали что надо юзать get_A()

// Пете нужна какая то левая либа в которой закрыты некие поля
#define private public
...
// Вася заинклюдил хидер Пети и не читает доки
auto S = Singlton();
AntonI ★★★★
()
Ответ на: комментарий от fluorite

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

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

Да хрен ты что от достаточно настойчивого плюсовика спрячешь. При желании можно и в .data-сегмент ручонками залезть :)

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

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

Ок, следите за руками:

ты сам понял, что написал?
конструктор должен быть приватным, а функция взять_синлетон - публичной статической функции класса.
тогда никто не сможет создать этот обьект, кроме функции класса.

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

Петя делает либу-обертку, где изолирует кукол вуду и прочую нехорошую некромантию. Вася юзает строго обертку, или не проходит кодревью :)

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

Это если Петя сделает обертку…

ЕМНИП от такого лефайна в каких то компайлерах даже заглушка была - очень был распотраненный прием при написании научного софта. Настоящие программисты от такого за голову хватались…

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

Ну нудеть то он от этого не перестанет…

Вообще в HPC страшные вещи творятся. Позвал меня коллега как то помочь код по молекулярной динамике собрать, автор кода - Нобелевский лауреат или типа того. Открываю архив, а там один .с файл на овер4000 строк.

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

до сих вспоминаю внезапные падения в продакшыне от того что новый админ заказчика в конфиг формат даты вписал не тот, а проверки формата, как оказалось, кто-то делал на коленке только сравнением длины строки — а чо, так быстрее же :)

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

Петя либо сделает сразу, чутка подумав, либо после разбора полетов Васи :)

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

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

class Singlet{
	int _x;
	Singlet(){_x=100;}

public:	
	static Singlet& singlet(){
		static Singlet __;
		return __;
	}
};

void ff(){
	Singlet s; //тут будет ошибка
	auto ls = Singlet::singlet(); //можно только так
}
alysnix ★★★
()
Ответ на: комментарий от slackwarrior

Фигасе, у вас там кто то проверял корректность конфига?!

Как то смежники по договору с МинОбр-ом прислали нам образец того как в отчете надо оформлять описание кода. В качестве образца кода был исходник какой то шни на дельфях которая рисовала форму на 40 полей и потом генерила конфиг. Шеф когда ЭТО увидел издал полустон-полувсхип и натурально потек со стула - мы думали сердце, скорую чуть не взывали…

После этого я перестал ругать студентов за неиспользуемые переменные.

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

Спасибо Кэп! Специально для Вас - первый пример в Почему статической ф-ии разрешено вызывать конструктор? (комментарий) не является синглтоном.

Прежде чем задорно кидаться кому то что то объяснять, подумайте - а нуждается ли этот кто то в Ваших объяснениях?;-)

ссылки, которая может быть константной

const T& ref = f();

((T&)ref).non_const_method(); // хааачу!
AntonI ★★★★
()
Последнее исправление: AntonI (всего исправлений: 1)
Ответ на: комментарий от AntonI

Это по-разному делается :) Сначала договариваются «у нас ответственные одмины, только скорость, только хардкор». Потом база клиентов расширяется — «других одминов у нас для вас нет — зделайте чтоб работало».

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

Спасибо Кэп! Специально для Вас - первый пример в Почему статической ф-ии разрешено вызывать конструктор? (комментарий) не является синглтоном.

да пожалста. правильно оформлять пост надо. высказывание - «ок, следите за руками» - это ни о чем. если б вы написали - «вот пример того, что не является правильным синглетоном», я б понял сразу. а «следите за руками»… так я за руками и следил.

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

Ежели Вы и правда хотите гарантий, то надо энтот синглтон делать полностью абстрактным, а наследника прятать в .cpp!;-)

Ну и const ref ничего не гарантирует, оставить тока геттеры в интерфейсе. Хотя ж блин все равно залезут… ;-( Можно правда .cpp не давать а давать только объектник.

Вот кодирование это тема, это и правда дает некоторую надежду что разработчику будет лень ломать и он пойдет прочитает доки/спросит;-)

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

Ежели Вы и правда хотите гарантий, то надо энтот синглтон делать полностью абстрактным, а наследника прятать в .cpp!;-)

это другая тема. это сокрытие реализации. а синглетон нужен прежде всего для об’ктов, что ПО ОПРЕДЕЛЕНИЮ существуют в одном экземпляре. и наличие двух и более экземпляром является или ошибкой, или злым умыслом.

alysnix ★★★
()

И сказано

Кем сказано? На то есть объективные причины - для вызова метода нужен this, у статической функции его нет. Для вызова конструктора this не нужен.

Ведь специально закрытым сделали

Ограничения видимости работают наружу класса, а не внутрь. В этом весь их смысл.

slovazap ★★★★★
()

Статические функции могут всё как и обычные внеклассовые функции, но им можно назначать доступность и они ввиду того, что они самые обычные ф-ии не могут непосредственно вызывать всё что имеет доступ к указателю this, поэтому они и могут вызывать почти всё что угодно для указателя на объект

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

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

…и потом не смочь в правильный порядок инициализации и даже не понять этого.

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

Можно просто делать синглетоны с явным init/destroy.

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

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

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

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

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

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

Что мешает сделать изолированную в одной единице трансляции глобальную переменную и функцию доступа к ней которая обеспечит инициализацию при первом обращении?

Такой вариант тут уже был.

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

Ты понимаешь, что для того, что бы не выглядеть глупо тебе пришлось утверждать, что глобальная переменная плюс функция доступа к ней - это ПРОСТО ГЛОБАЛЬНАЯ ПЕРЕМЕННАЯ, точно не сингтон. Удачи.

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

Что мешает сделать изолированную в одной единице трансляции глобальную переменную и функцию доступа к ней которая обеспечит инициализацию при первом обращении?

Это и есть синглетон.

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

как тут структура из массивов с минимумом накладных расходов (комментарий)

И где там модификация структуры полей в рантайме?

Или ты под модификацией рантайме имел ввиду изменение размеров массива, только сделал это очень странным образом: «может быть просто поле типа T, а может быть небольшой массив (одномерный или двумерный), и это будет меняться в runtime»?

Никогда бы не подумал что под это описание подходит двумерный массив на макросах с претензией на «производительность» (медленнее чем std::vector).

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

Это и есть синглетон.

Нет. Это не гарантирует что НЕ будет создан еще один экземпляр того же класса. Но это может решать те же задачи что и решает синглтон. Учите матчасть.

И изначально ты спорил имея ввиду…

Я Вам уже выше писал, что Вы не умеете читать и понимать написанное.

ты под модификацией рантайме имел ввиду изменение размеров массива, только сделал это очень странным образом: «может быть просто поле типа T, а может быть небольшой массив (одномерный или двумерный), и это будет меняться в runtime»?

Да. Задача ставится именно так.

Никогда бы не подумал что под это описание подходит двумерный массив на макросах с претензией на «производительность» (медленнее чем std::vector).

Что именно там медленнее чем std::vector? Можете предложить как сделать быстрее?

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

Это не гарантирует что НЕ будет создан еще один экземпляр того же класса.

Единственное СЕМАНТИЧЕСКОЕ отличие синглтона - возможна отложенная инициализация (при первом обращении). Для обычной глобальной переменной это будет сделать сложнее/костыльнее.

Удобно.

Я Вам уже выше писал, что Вы не умеете читать и понимать написанное.

Что именно там медленнее чем std::vector? Можете предложить как сделать быстрее?

Тред прочитай.

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

Тред прочитай.

Это не ответ, особенно от Вас. Всего хорошего.

AntonI ★★★★
()
Последнее исправление: AntonI (всего исправлений: 1)

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

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