Олександр Ковальчук написав:З вашого дозволу ще одне питяння.
Маю таку конструкцію:
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. І так, повертати
погана ідея, хіба що у вас є гарантія, що тип Т завжди default constructible.