Тема: Об'єкт на позначення відсутності в списку

З вашого дозволу ще одне питяння.
Маю таку конструкцію:

T operator [](int index)
    {
        if (isEmpty() || index > lenght - 1)  return T{};
        return find(index)->data;
    }


Оператор повертає значення елементу списку за його індексом.
У разі коли список пустий чи індекс перевищує кількість елементів в списку він повертає дефолтний конструктор типу(T{}).
І я розумію що це не зовсім хороша ідея,оскільки це працює лише в тому випадку коли T - вказівник і оператор поверне nullptr.
У випадку коли T простий тип (int наприклад) то оператор поверне 0...і не зрозуміло чи це помилка чи значення елементу списку.Як правильно вирішити цю проблему?

2

Re: Об'єкт на позначення відсутності в списку

Виділив у окрему тему за п.3.6 Правил.

3

Re: Об'єкт на позначення відсутності в списку

Це питання до семантики вашої програми. Якщо ви в курсі, що 0 означає помилку, то будете його так і обробляти. У int немає "прихованих" значень, які не могли б набуватися без помилок.
Як вийти з цього?
1. У вас усе ж таки список (об'єкти лежать у пам'яті), тобто можете повертати покликання на const T або nullptr.
2. Можете повертати std::pair<bool, T>, де перший елемент вказуватиме, чи вдало спрацювала функція.
3. Можете у випадку неправильного індексу кидати виключення. Виключення - теж повернення з функції, щоправда, аварійне.

І, до речі, ви не розбираєте ситуацію з від'ємним індексом.

Подякували: leofun011

4

Re: Об'єкт на позначення відсутності в списку

А, ще можна створити власний тип з функціональністю int, але декілька значень (на кшталт INT_MIN) використовувалися б як коди помилок.

5 Востаннє редагувалося wander (24.07.2022 22:23:04)

Re: Об'єкт на позначення відсутності в списку

Олександр Ковальчук написав:

З вашого дозволу ще одне питяння.
Маю таку конструкцію:

T operator [](int index)
    {
        if (isEmpty() || index > lenght - 1)  return T{};
        return find(index)->data;
    }


Оператор повертає значення елементу списку за його індексом.
У разі коли список пустий чи індекс перевищує кількість елементів в списку він повертає дефолтний конструктор типу(T{}).
І я розумію що це не зовсім хороша ідея,оскільки це працює лише в тому випадку коли T - вказівник і оператор поверне nullptr.
У випадку коли T простий тип (int наприклад) то оператор поверне 0...і не зрозуміло чи це помилка чи значення елементу списку.Як правильно вирішити цю проблему?

Гм, трохи дивно, що у вас список має operator[]. Наявність можливості робити типу fast random access, як це доступно масивам, може вводити користувачів в оману. Наприклад, той же std::list зі стандартної бібліотеки не підтримує такого функціоналу з очевидних причин. Отримання елемента за індексом — це операція O(1), тож надання operator[] буде оманливим, оскільки у користувачів буде спокуса активно його використовувати, і тоді можна буде бачити такий код:

List<int> list;
for (i = 0; i < list.size(); ++i) {
    int x = list[i];
    // ...
}

, який насправді буде O(n^2)/O(n). Саме тому, у стандарті С++ спеціально згадується, що всі послідовності STL, які підтримують operator[], повинні робити це за амортизований постійний час (http://eel.is/c++draft/sequence.reqmts#69).
Так, ви, звісно, не зобов'язані дотримуватись тих же гарантій, що надає стандарт, які і ваш контейнер не зобов'язаний бути схожим на відповідники зі стандартної бібліотеки. Але все ж, я б оглядався на STL, в ідеалі, звісно б взагалі писати контейнери зі збереженням сумісності з STL. Як не крути, але стандартною бібліотекою все ж користуються, де це можливо і для багатьох вона є знайомою, тому.. Я б надавав такий оператор, лише якщо була б гарантія О(1).

Гаразд, це був ліричний відступ. Тепер більш конкретно (в додачу до всього вище сказаного) по вашому operator[]. Я б повертав покликання (як вже згадував пан koala) — T& або T const&. З гарантіями типу:

Повертає елемент по індексу i як ... покликання. i має бути валідною позицією в списку (тобто 0 <= i < size()), інакше UB.

std::pair<bool, T> я б не повертав і виключення теж би не кидав. Ще, як варіант я б розглянув хіба що std::optional. І так, повертати

return T{};

погана ідея, хіба що у вас є гарантія, що тип Т завжди default constructible.

Подякували: leofun01, koala2