【问题标题】:Usage of FLAGS_nono##name in gflags source code在 gflags 源代码中使用 FLAGS_nono##name
【发布时间】:2014-12-22 08:28:10
【问题描述】:

我最近正在阅读 gflags 的源代码。而且这里的评论真的让我很困惑。

它是说引入 FLAGS_nono##name 以确保静态初始化。但据我所知,如果您定义一个全局变量,例如: 整数 x = 20;

x 仍然是静态初始化的。 FLAGS_nono##name 这里有什么必要。

我理解错了吗?

谢谢。

// 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 @GFLAGS_NAMESPACE@::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 类。 我想知道这样的类和全局变量的必要性是什么,而不是简单地定义一个函数。

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
}

【问题讨论】:

    标签: c++ gflags


    【解决方案1】:

    你说得对,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 @GFLAGS_NAMESPACE@::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 @GFLAGS_NAMESPACE@::FlagRegisterer o_##name( \
          #name, #type, MAYBE_STRIPPED_HELP(help), __FILE__,                \
          &FLAGS_##name, &FLAGS_no##name);                                  \
      }                                                                     \
      using fL##shorttype::FLAGS_##name
    

    但是现在你已经有了动态初始化,你需要静态初始化。

    为了确保两者都能正常工作,您需要一个额外的辅助变量,这就是您所询问的代码所做的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-10
      • 2011-01-28
      • 2010-09-24
      • 2014-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      相关资源
      最近更新 更多