Skip to content

Incorrect initialization of default-values in FindOrDefault #1186

Description

@ddvamp

return (ptr ? *ptr : decltype(*ptr){std::forward<Default>(def)});

return (ptr ? *ptr : decltype(*ptr){});

Предполагаю, что в функции FindOrDefault без предоставленного default-а, если ключ отсутствует, намерением было возвращать default-constructed объект. Однако при создании объекта по форме T{} возможно попасть в случай, когда тип T не имеет default конструктора, но имеет конструктор от std::initializer_list. В этом случае поведение не будет соответствовать ожидаемому.

Пример: https://godbolt.org/z/TfxW1fY6s

Возможно правильным будет осуществлять инициализацию по форме T(), однако это приведёт к исчезновению агрегатной инициализации. Также, для единообразности вида и поведения, использовать T(std::forward<Default>(def)) для инициализации default значением (также исключить init-list-constructors).

При попытке осуществить это раскрывается вторая проблема. Тип decltype(*ptr) является ссылкой, а не значением. Поэтому при создании default результата в функциях FindOrDefault сперва инициализируется ссылка, которая затем используется для copy инициализации результата (https://eel.is/c++draft/expr.type.conv#1.3).

Пример: https://godbolt.org/z/eEvrMEfvM

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions