2014-12-22 3 views
0

Недавно я читаю исходный код gflags. И комментарий здесь меня действительно смущает.Использование FLAGS_nono ## name в gflags исходный код

Говорят, что FLAGS_nono ## вводится для обеспечения статической инициализации. Но, насколько я знаю, если вы определяете глобальную переменную типа: int x = 20;

x все еще статически инициализирован. В чем заключается необходимость имени FLAGS_nono ## здесь.

Не понимаю ли это?

Спасибо.

// Each command-line flag has two variables associated with it: one 
// with the current value, and one with the default value. However, 
// we have a third variable, which is where value is assigned; it's a 
// constant. This guarantees that FLAG_##value is initialized at 
// static initialization time (e.g. before program-start) rather than 
// than global construction time (which is after program-start but 
// before main), at least when 'value' is a compile-time constant. We 
// use a small trick for the "default value" variable, and call it 
// FLAGS_no<name>. This serves the second purpose of assuring a 
// compile error if someone tries to define a flag named no<name> 
// which is illegal (--foo and --nofoo both affect the "foo" flag). 
#define DEFINE_VARIABLE(type, shorttype, name, value, help)    \ 
    namespace fL##shorttype {            \ 
    static const type FLAGS_nono##name = value;       \ 
    /* We always want to export defined variables, dll or no */   \ 
    GFLAGS_DLL_DEFINE_FLAG type FLAGS_##name = FLAGS_nono##name;  \ 
    type FLAGS_no##name = FLAGS_nono##name;        \ 
    static @[email protected]::FlagRegisterer o_##name(\ 
     #name, #type, MAYBE_STRIPPED_HELP(help), __FILE__,    \ 
     &FLAGS_##name, &FLAGS_no##name);         \ 
    }                  \ 
    using fL##shorttype::FLAGS_##name 

Для более контекста см https://code.google.com/p/gflags/source/browse/src/gflags.h.in#471

Другой вопрос класс FlagRegisterer используется в кодах, упомянутых выше. Мне интересно, какая необходимость такого класса и глобального var здесь, а не просто определение функции.

class GFLAGS_DLL_DECL FlagRegisterer { 
public: 
    FlagRegisterer(const char* name, const char* type, 
       const char* help, const char* filename, 
       void* current_storage, void* defvalue_storage); 
}; 


// -------------------------------------------------------------------- 
// FlagRegisterer 
// This class exists merely to have a global constructor (the 
// kind that runs before main(), that goes an initializes each 
// flag that's been declared. Note that it's very important we 
// don't have a destructor that deletes flag_, because that would 
// cause us to delete current_storage/defvalue_storage as well, 
// which can cause a crash if anything tries to access the flag 
// values in a global destructor. 
// -------------------------------------------------------------------- 

FlagRegisterer::FlagRegisterer(const char* name, const char* type, 
           const char* help, const char* filename, 
           void* current_storage, void* defvalue_storage) { 
    if (help == NULL) 
    help = ""; 
    // FlagValue expects the type-name to not include any namespace 
    // components, so we get rid of those, if any. 
    if (strchr(type, ':')) 
    type = strrchr(type, ':') + 1; 
    FlagValue* current = new FlagValue(current_storage, type, false); 
    FlagValue* defvalue = new FlagValue(defvalue_storage, type, false); 
    // Importantly, flag_ will never be deleted, so storage is always good. 
    CommandLineFlag* flag = new CommandLineFlag(name, help, filename, 
               current, defvalue); 
    FlagRegistry::GlobalRegistry()->RegisterFlag(flag); // default registry 
} 

ответ

0

Вы правы, что-то вроде int i = 10; выполняет статическую инициализацию. Поэтому можно было бы написать

#define DEFINE_VARIABLE(type, shorttype, name, value, help)    \ 
    namespace fL##shorttype {            \ 
    /* We always want to export defined variables, dll or no */   \ 
    GFLAGS_DLL_DEFINE_FLAG type FLAGS_##name = value;     \ 
    type FLAGS_no##name = value;          \ 
    static @[email protected]::FlagRegisterer o_##name(\ 
     #name, #type, MAYBE_STRIPPED_HELP(help), __FILE__,    \ 
     &FLAGS_##name, &FLAGS_no##name);         \ 
    }                  \ 
    using fL##shorttype::FLAGS_##name 

Однако будьте осторожны, это макрос. Несколько ссылок на value вызывают множественные расширения. Если valueне константа, если она содержит, например, вызов функции, это вызовет вызов функции дважды.

Этого можно избежать путем копирования одной переменной в другую:

#define DEFINE_VARIABLE(type, shorttype, name, value, help)    \ 
    namespace fL##shorttype {            \ 
    /* We always want to export defined variables, dll or no */   \ 
    GFLAGS_DLL_DEFINE_FLAG type FLAGS_##name = value;     \ 
    type FLAGS_no##name = FLAGS_##name;         \ 
    static @[email protected]::FlagRegisterer o_##name(\ 
     #name, #type, MAYBE_STRIPPED_HELP(help), __FILE__,    \ 
     &FLAGS_##name, &FLAGS_no##name);         \ 
    }                  \ 
    using fL##shorttype::FLAGS_##name 

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^