Найти в Дзене
Deep Software Engeneering

Два бага, которые я сделал в C++ коде на этой неделе

Код почти всегда содержит баги. Просто они не видны до поры, до времени. Сегодня хочу поговорить о тех, которые запомнились на этой неделе. std::optional::value_or Сможете найти ошибку без подсказки? Вероятно, потому что я еще не до конца привык к optional... Но идея в том, что, конечно же, в C++ нет ленивых вычислений, как в Haskell. Поэтому аргументы функций должны быть известны на момент её вызова. Ошибка в том, что функция f() вычисляется дважды, даже если результат её вычисления уже есть в кэше. Исправленный код: Шаблонный конструктор копирования Тут довольно непростой пример, но я дам пояснения "чего же я хотел", У меня есть класс SerializedStorage, который принимает на вход что угодно и хранит это что угодно в строковом формате. Мои ожидания от вывода программы: SerializedStorage(SerializedStorage(10)). На самом деле, программа сейчас выводит SerializedStorage(10). Почему это произошло? Потому что в C++ создание шаблонного конструктора не считается переопределением конструктора.
Оглавление

Код почти всегда содержит баги. Просто они не видны до поры, до времени. Сегодня хочу поговорить о тех, которые запомнились на этой неделе.

std::optional::value_or

Сможете найти ошибку без подсказки?

Вероятно, потому что я еще не до конца привык к optional... Но идея в том, что, конечно же, в C++ нет ленивых вычислений, как в Haskell. Поэтому аргументы функций должны быть известны на момент её вызова. Ошибка в том, что функция f() вычисляется дважды, даже если результат её вычисления уже есть в кэше. Исправленный код:

-2

Шаблонный конструктор копирования

Тут довольно непростой пример, но я дам пояснения "чего же я хотел",

-3

У меня есть класс SerializedStorage, который принимает на вход что угодно и хранит это что угодно в строковом формате. Мои ожидания от вывода программы: SerializedStorage(SerializedStorage(10)). На самом деле, программа сейчас выводит SerializedStorage(10). Почему это произошло?

Потому что в C++ создание шаблонного конструктора не считается переопределением конструктора. Таким образом, конструктор копирования по умолчанию остается определен. Именно он и вызвался для строки SerializedStorage g(a). То есть g не "обернуло и сериализовало" a, а просто скопировало serialized_value. Что же делать?

Первая мысль — удалить конструктор копирования.

-4

Пёс!

error: call to deleted constructor of 'SerializedStorage'

Удаленный конструктор не заставляет компилятор попробовать что-то еще. Решение пришлось искать очень долго, но оно есть: удалить const volatile конструктор копирования. Он более "специализированный", и поэтому в этом случае обычный конструктор копирования не генерируется компилятором.

-5

Добро!

SerializedStorage(SerializedStorage(10))

Спасибо всем, кто дочитал! Будьте бдительны!