Вызов конструктора против определения встроенной константы в качестве параметра по умолчанию - PullRequest
1 голос
/ 23 октября 2019

У меня есть функция, которая имеет конфигурационную структуру в качестве аргумента

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

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

Определение Config() и computeSomethingFrom(...) находятся в одном исходном файле.

MyПредполагается, что каждый вызов функции будет вынужден создавать Config, поскольку нет способа узнать, зависит ли конструктор по умолчанию от чего-то еще в среде. Это может дорого обойтись, если структура конфигурации становится большой или функция вызывается много раз.

Тем не менее, я бы предпочел не создавать другую константу, если смогу. И это возможно , учитывая, что конструктор по умолчанию и функция определены в одном и том же исходном файле, и компилятор может сделать вывод, что Config() всегда возвращает одно и то же.

Так что естьлюбой способ избежать выполнения чего-то вроде

inline Config DEFAULT_CONFIG = Config();

и последующего объявления функции как

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

?

Ответы [ 4 ]

6 голосов
/ 23 октября 2019

Просто перегрузите эту функцию:

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);
}
3 голосов
/ 23 октября 2019

Так есть ли способ избежать выполнения чего-то вроде

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 голосов
/ 23 октября 2019

Если вы не хотите загрязнять глобальное пространство экземпляром по умолчанию и хотите избегать создания объекта при каждом вызове функции, тогда я бы предложил перегрузить функцию. Есть одна версия, которая принимает 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);
}
2 голосов
/ 23 октября 2019

Я предполагаю, что каждый вызов функции будет вынужден создавать Config, поскольку нет способа узнать, зависит ли конструктор по умолчанию от чего-то другого в среде.

Вы быпоражен тем, что может сделать любой современный компилятор. Весь пустой код будет оптимизирован. Вы хотите сосредоточиться на большей читабельности, а не пытаться угадать компилятор. Только после того, как вы выполнили анализ производительности выполняемого кода и обнаружили узкое место, попробуйте выполнить некоторую оптимизацию.

...