管理命令行参数

3

我正在更新一些旧代码,原始作者决定将所有命令行参数变量设为全局变量。这显然会增加测试和开发方面的挑战。

我的问题是,如何最好地管理所有类都需要使用的命令行参数(例如跟踪标志/调试标志)。一位同事建议至少将变量包装在命名空间中,但那似乎并不足够。我考虑过单例或静态类,并提供getter方法,但那似乎不太优雅。另一方面,这似乎比需要向每个需要知道是否启用调试和其他一些选项的类传递5个配置选项要好。

2个回答

4
全局变量最大的问题是在函数内部改变它们往往会导致意外的副作用,从而引入错误。然而,在命令行参数的情况下,它们对于运行进程来说实际上是常量。唯一阻止你声明它们为const的事情是需要在开始解析命令行时进行赋值。
我建议创建某种机制,允许您在开头初始化参数,但随后防止程序的任何部分更改它们。这将有效避免通常引入的任何全局变量的不利影响。
一种方法可能是创建一个ProgramArguments类/结构,其中包含由构造函数通过解析命令行初始化的const成员。然后,您可以像这样:
std::unique_ptr<ProgramArguments const> g_program_arguments;

int main(int argc, char* argv[])
{
    g_program_arguments.reset(new ProgramArguments(argc, argv));
    if(g_program_arguments->verbose)
        std::cout << "verbose!" << std::endl;
    // ...
    return 0;
}

这并不会阻止您将指针更改为指向其他 ProgramArguments 实例。另一种方法是暂时取消 const 属性以进行初始化:

struct ProgramArguments {
    ProgramArguments() {}
    bool verbose;
};

ProgramArguments const g_program_arguments;

void init_program_arguments(int argc, char* argv[])
{    
    ProgramArguments& program_arguments = const_cast<ProgramArguments&>(g_program_arguments);
    program_arguments.verbose = true;
}

int main(int argc, char* argv[])
{
    init_program_arguments(argc, argv);
    if(g_program_arguments.verbose)
        std::cout << "verbose!" << std::endl;
    return 0;
}

我真的很喜欢这个方法。比单例模式还要好。虽然可以像你提到的那样做一些有趣的指针操作,但没关系。 - LeviX

0

这将取决于我们所讨论的全局变量数量。个人认为,对于像调试标志和单例日志管理器之类的东西,拥有一些全局变量是可以接受的。

如果你真的想要完全遵守面向对象编程原则,那么你必须将函数或对象需要的所有内容作为参数传递。永远不要访问全局状态。正如你所提到的,将许多常见参数传递给每个函数很快就会变得乏味,因此可能有一种模式可以帮助你缓解这种情况,那就是上下文对象


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接