Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

not enough stack, let's use heap instead(sdBrowserMenu) #8

Merged
merged 12 commits into from
Mar 19, 2024
Merged

not enough stack, let's use heap instead(sdBrowserMenu) #8

merged 12 commits into from
Mar 19, 2024

Conversation

frostmorn
Copy link
Collaborator

Should work, but can't check :)

Copy link
Owner

@and3rson and3rson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Дякую за PR! Декілька проблем:

  • Змінна File file в sdcard.cpp:116 ініціалізується повторно всередині do {}. Це призводить до шедовінгу зовнішньої змінної, яка залишається неініціалізованою. Тому цикл виконується лише 1 раз.
  • Пам'ять виділяється лише на _numEntries файлів, але їх потрібно _numEntries + 1 (ще є пункт "<< Назад")
  • Замість new, можна ініціалізувати entries/filenames/etc в стеку:
    lilka::Entry entries[_numEntries];
    Це спростить менеджмент пам'яті, і не потрібно буде слідкувати за всіма return-ами, щоб там зробити delete.
  • Потрібно переформатувати код через clang-format (див. зафейлені перевірки)
  • Я особисто б уникав do {} while() - як на мене, while() {} читабельніший. Але то не критично. :)
  • Краще назвати метод getEntryCount - він натякає на отримання чогось

serial_err("countFilesInDir listDir: not a directory: %s", path.c_str());
return 0;
}
File file;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ось перша ініціалізація, а в рядку 112 - повторна (shadowing). Відповідно, в while використовується оця (яка залишається неініціалізованою)

@and3rson
Copy link
Owner

and3rson commented Mar 18, 2024

Якщо хочеш використовувати саме купу замість стеку - то можна залишити new, але оскільки нещовдавно в menu з'явився метод addItem (і ці filenames/icons/colors - це пережиток зі старого меню, яке хотіло масиви), нам більше не потрібно виділяти пам'ять для іконок наперед, можна наповнювати його на льоту, і потрібно виділити пам'ять лише для Entry[]. Якось так:

    lilka::Menu menu("SD: " + path); // Створюємо меню відразу
    size_t numEntries = lilka::sdcard.countFilesInDir(path);
    lilka::Entry *entries = new lilka::Entry[numEntries]; // Видяліємо пам'ять для entries
    lilka::sdcard.listDir(path, entries);
    for (int i = 0; i < numEntries; i++) {
        // Додаємо пункти на льоту, без виділення пам'яті для масивів назв/іконок/кольорів
        menu.addItem(
            entries[i].name, 
            entries[i].type == lilka::EntryType::ENT_DIRECTORY ? &folder : get_file_icon(filenames[i]),
            lilka::EntryType::ENT_DIRECTORY ? lilka::display.color565(255, 255, 200) : get_file_color(filenames[i])
        );
    }
    // Зразу звільняємо пам'ять:
    delete[] entries;
    // Все чисто, Menu само звільнить свою пам'ять, купа тепер чиста :)

@frostmorn
Copy link
Collaborator Author

Там сама суть була якраз в тому що ми не можемо знати скільки файлів у директорії тому немає що і виділяти у стеку. Більше ніж 32 файли і воно гарантовано впаде. Повторної декларації змінної не помітив. :D та й таке

@frostmorn frostmorn requested a review from and3rson March 19, 2024 01:30
@frostmorn
Copy link
Collaborator Author

не можу знайти в коді місце де оброблюється кнопка "<< Назад", та і в entries вона аж ніяк не додається, скоріше за все в попередній реалізації в стеку в entries[numEntries-1].name буде якесь сміття яке й заставить повернутися назад через return в попередній нескінченний цикл while :)
тому здається так має бути краще

@and3rson
Copy link
Owner

and3rson commented Mar 19, 2024

Значно краще!

Ще одне зауваження: оскільки там всякі break/return, в майбутньому може виникнути випадковий витік пам'яті, і потрібно буде пам'ятати викликати delete перед кожним return. Замість явного delete можна додати std::unique_ptr, який автоматично очистить пам'ять:

     lilka::Entry* entries = new lilka::Entry[_numEntries];
+    std::unique_ptr<lilka::Entry[]> entriesPtr(entries);
// ...
-         delete[] entries;
// ...
-    delete[] entries;

Коли entriesPtr вийде за межі області видимості (в даному випадку - функції), він автоматично звільнить пам'ять entries.

@frostmorn
Copy link
Collaborator Author

звісно це вже зовсім прискіпливо, хоча на одну стрічку кода менше, чому ні =)

@and3rson
Copy link
Owner

Затестив - все працює. Дякую!

@and3rson and3rson merged commit 605d0b9 into and3rson:main Mar 19, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants