调用构造函数与将内联常量定义为默认参数

时间:2019-10-23 13:04:50

标签: c++ c++17

我有一个将配置结构作为参数的函数

struct Config
{
  Config(); //<-- default constructor
  // some configuration constants
};

int computeSomethingFrom(Something arg, const Config& config = Config());

Config()computeSomethingFrom(...)的定义都在同一个源文件中。

我的猜测是,每个函数调用都将被强制构造Config,因为无法知道默认构造函数是否依赖于环境中的其他内容。如果配置结构变大或函数被多次调用,这可能会变得昂贵。

不过,如果可以的话,我宁愿避免创建另一个常量。并且可能,因为默认构造函数和函数是在同一个源文件中定义的,因此编译器可以推断Config()总是返回相同的东西。

那么有什么方法可以避免做类似的事情

inline Config DEFAULT_CONFIG = Config();

,然后将该函数声明为

int computeSomethingFrom(Something arg, const Config& config = DEFAULT_CONFIG);

4 个答案:

答案 0 :(得分:6)

只需重载此功能:

int computeSomethingFrom(Something arg, const Config& config); // note no default value
int computeSomethingFrom(Something arg);

我不知道这会如何影响您的代码,因为您没有提供任何信息computeSomethingFrom

一种可能的实现方式(可能您对此不会满意):

int computeSomethingFrom(Something arg)
{
    static const Config cfg;
    return computeSomethingFrom(arg, cfg);
}

答案 1 :(得分:3)

  

那么有什么方法可以避免做类似的事情

inline Config DEFAULT_CONFIG = Config();
     

,然后将该函数声明为

int computeSomethingFrom(Something arg, const Config& config = DEFAULT_CONFIG);

您确实可以声明全局(在文件范围内)并使用:

/*static*/ const Config DEFAULT_CONFIG = Config();
int computeSomethingFrom(Something arg, const Config& config = DEFAULT_CONFIG);

即使您不需要它,也将在“开始”时调用构造函数一次(与其他全局变量一样)。

您可能会这样创建一个“惰性”工厂:

const Config& DefaultConfig() {
    static Config config; // Call only once
    return config;
}

int computeSomethingFrom(Something arg, const Config& config = DefaultConfig());

主要与其他带有重载的提案一样

int computeSomethingFrom(Something arg, const Config& config);
int computeSomethingFrom(Something arg)
{
    static const Config config;

    return computeSomethingFrom(arg, config);
}

但处理同一功能的多个默认参数,
并为多个功能处理相同的默认值。

答案 2 :(得分:2)

  

我的猜测是,每个函数调用都将被强制构造Config,因为无法知道默认构造函数是否依赖于环境中的其他内容。

您会惊讶于任何现代编译器可以做什么。所有空代码将被优化掉。您想要集中更多的可读性,而不是试图猜测编译器。只有对运行的代码进行了性能分析并确定了瓶颈之后,再尝试在那里进行一些优化。

答案 3 :(得分:2)

如果您不想使用默认实例污染全局空间,并且希望避免在每个函数调用中创建对象,那么我建议重载该函数。有一个版本使用Config,而另一个版本则不需要。然后,在没有创建的static Config中创建一个实例。由于静态变量需要某种保护以确保它们不会被多次初始化,因此这仍然会有少量的开销。看起来像

int computeSomethingFrom(Something arg, const Config& config)
{
    // do the stuff
}
int computeSomethingFrom(Something arg)
{
    static Config config{};
    computeSomethingFrom(std::move(arg), config);
}