Возможно ли сделать аналог синглтона майерса в си?
Я не хочу делать глобальную переменную, потому что она доставляет массу неудобство с дебагом. Могу ли я сделать что то похожее на синглтон майерса?
static char* init(){
static char* test = malloc(30);
return test;
}
Компилятор выдает следующую ошибку
Initializer element is not a compile-time constant
Ответы (4 шт):
char* init() {
static char* test = NULL;
if (test == NULL) test = malloc(30);
return test;
}
Лисп язык (LISP) подсказал идею : функцию init сделать указателем на функцию. Сначала она будет указывать на инициализацию, а дальше просто возвращать значение. Но этот указатель никто не защищает. Если его не трогать будет всё работать.
singlet.h
// тип функции
typedef char * ( * singleton_functype ) ( void ) ;
// указатель на неё
extern singleton_functype init ;
singletmain.c
// gcc -Wall -Wextra -Wpedantic -Winline -Wshadow -Wconversion -std=c11 -Os singlet.c singletmain.c -o singlet
# include <stdio.h>
# include "singlet.h"
int main(){
puts("main:begin");
char * st = init ( ) ;
* st = '\00' ;
puts("main:next");
init ( ) ;
puts("main:end");
}
singlet.c
# include <stdio.h>
# include <stdlib.h>
# include "singlet.h"
// указатель виден только внутри данного файла
static char * test ;
// возвращаем уже готовый указатель
char * singleton_work ( void ) {
puts("singleton_work");
return test ;
}
// выделяем память И меняем указатель рабочей функции
char * singleton_init ( void ) {
puts("singleton_init");
test = malloc ( 30 ) ;
init = singleton_work ;
return test ;
}
// сначала указываем на функцию с выделением памяти
singleton_functype init = singleton_init ;
проверяем :
> ./singlet
main:begin
singleton_init
main:next
singleton_work
main:end
Синглетон (без следов Майерса): не занимается созданием или уничтожением экземпляра, только разделяет владением им и предоставляет к нему доступ:
static char * s_p_instance = NULL;
void instance_set(char * p_instance)
{
assert(! s_p_instance);
s_p_instance = p_instance;
assert(s_p_instance);
return;
}
void instance_reset(void)
{
s_p_instance = NULL;
return;
}
char * instance_fetch(void)
{
assert(s_p_instance);
return s_p_instance ;
}
Использование:
int main()
{
char * p_instance = (char *) calloc(30, 1);
instance_set(p_instance);
...
puts(instance_fetch());
...
instance_reset();
free(p_instance);
}