Open unterumarmung opened 3 years ago
Если сделать noexcept(N != 0)
, то оба свойства будут присутствовать. Или так нельзя?
Если сделать
noexcept(N != 0)
, то оба свойства будут присутствовать. Или так нельзя?
UB не исчезнет, noexcept
'ность конечно появится
А для каких целей используется std::array с нулевой длинной?
template<size_t N>
constexpr std::optional<int> first_worker_weight(const std::array<int, N>& arr) {
if constexpr(N == 0) {
return std::nullopt;
}
return arr[0]; // or arr.front()
}
template<size_t N>
constexpr int sum_workers_weight(const std::array<int, N>& arr) {
int result = 0;
for (size_t i = 0; i < N; ++i) {
result += arr[i];
}
return result;
}
Код такого вида корректен, но его компиляция будет сломана при N = 0. Чтобы чинить компиляцию такого кода, придется использовать: 1) at() с доп. проверкой внутри 2) итератор, который убьет читаемость в некоторых случаях. К тому же не ясно сколько кода придется починить .
Если с front и back понятно, что легко ошибиться и можно оградиться от ошибок, то не понятно зачем ломать интерфейс с operator[] ? Сейчас std::array<T,N>::operator[] имеет УБ, если обращаться к несуществующему элементу. Для этого случая логика такая же. Кто пользуется индексами сам проверяет их корректность.
p.s. If size() is 0, data() may or may not return a null pointer.
может и тут починить?
Чтобы чинить компиляцию такого кода, придется использовать: 1) at() с доп. проверкой внутри 2) итератор, который убьет читаемость в некоторых случаях.
Или поставить else
:)
Или поставить
else
:)
На мой взгляд, это органично только для первого примера, использовать такое везде не очень удобно.
Код такого вида корректен, но его компиляция будет сломана при N = 0.
Да, есть проблема с тем, что в C++ везде есть код по типу:
if (xxx) {
// обычный код...
} else {
// тоже обычный код, но который при (xxx == true) генерировал бы ЖОСКИЙ UB
}
когда рантаймовые ошибки переводятся в ошибки компиляции (как в этом issue), за это придется заплатить:
if constexpr (xxx) {
// ...
} else {
// ...
}
Но во многих местах мы не можем просто добавить constexpr
, потому что xxx
может не быть вычислимым на этапе компиляции.
Я бы предложил сделать некую статическую проверку для компилятора, который будет выдавать warning, если рантайм в теории может привести к UB. Но таких проверок и так несколько сотен, и ни одна не предложит переделать такое:
#include <iostream>
#include <array>
int main() {
std::array<int, 128> arr;
int v;
std::cin >> v; // вводится 100500
std::cout << arr[v] << std::endl;
}
В текущем варианте функции
front
,back
,operator[]
имеют неопределенное поведение, еслиarray.size() == 0
. Данное решение видимо было сделано, чтобы специализацииstd::array<T, 0>
удовлетворяли требованиюSequenceContainer
. Но точно ли массив нулевого размера является sequence container? Тем более, на cppreference указано, что дляstd::array
есть исключения.Удаление перегрузок данных перегрузок имеет два преимущества:
noexcept
, так как в них больше нет UB.Недостаток один:
std::array<T, 0>
перестают удовлетворять требованиюSequenceContainer
. Кажется, это не является большой потерей.Псевдокод реализации: