• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Menu w C++ - błąd wykonania programu

0 głosów
108 wizyt
pytanie zadane 23 lutego w C i C++ przez whiteman808 Gaduła (4,660 p.)

Jakiś pomysł skąd błędy w trakcie wykonania programu? Wyjście z terminala poniżej:

~/programy_cpp/linked_list ❯ cat menu.h                                                                                                         ✘ IOT 13:06:46
#ifndef MENU_H
#define MENU_H

#include <iostream>
#include <string>
#include <vector>
#include <functional>

using menu_item_func = std::function<void()>;

void print_title(const std::string& title);

struct menu_item {
    menu_item(const std::string& title_val) : title{title_val} {}
    menu_item(const std::string& title_val, menu_item_func action_val)
        : title{title_val}, action{action_val} {}
    menu_item(const menu_item& item) : title{item.title}, action{item.action} {}
    menu_item& operator=(const menu_item& rhs);

    friend std::ostream& operator<<(std::ostream& lhs, const menu_item& rhs);

    std::string title{};
    menu_item_func action{};
};

using menu_items = std::vector<menu_item>;

class menu {
public:
    menu(const std::string& title_val);
    menu(const std::string& title_val, const std::vector<menu_item>& items_val);
    menu(const menu& menu_val);

    void loop();

    static void noop() { std::cout << "No action defined!\n"; }

private:
    void print_choices() const;
    char read_choice() const;

    static int nesting_level;
    bool active{false};
    std::string title{};
    std::vector<menu_item> items{};
};

#endif // MENU_H
~/programy_cpp/linked_list ❯ cat menu.cpp                                                                                                             13:07:39
#include "menu.h"

int menu::nesting_level = 0;

void print_title(const std::string& title) {
    std::size_t title_len = title.size();
    std::size_t width = title_len + 4;
    for (int i = 0; i < width; ++i) {
        std::cout << "*";
    }
    std::cout << "\n* " << title << " *\n";
    for (int i = 0; i < width; ++i) {
        std::cout << "*";
    }
    std::cout << std::endl;
}

menu_item& menu_item::operator=(const menu_item& rhs) {
    title = rhs.title;
    action = rhs.action;
    return *this;
}

std::ostream& operator<<(std::ostream& lhs, const menu_item& rhs) {
    return lhs << rhs.title;
}

menu::menu(const std::string& title_val) : title{title_val} {
}

menu::menu(const std::string& title_val, const std::vector<menu_item>& items_val)
    : title{title_val}, items{items_val} {
}

menu::menu(const menu& menu_val) {
    for (const menu_item& item : menu_val.items) {
        items.push_back(item);
    }
}

void menu::print_choices() const {
    for (int i = 0; i < items.size(); ++i) {
        std::cout << i << ") " << items[i] << std::endl;
    }
    std::cout << "q) ";
    if (nesting_level > 1)
        std::cout << "Back";
    else
        std::cout << "Quit";
    std::cout << std::endl;
}

char menu::read_choice() const {
    char choice;
    bool valid{false};

    std::cout << "What do you want to do?\n";
    do {
        print_choices();
        std::cout << "Your choice: ";
        std::cin >> choice;
        if ((choice - '0') < 0 || ((choice - '0') >= items.size()) && (choice != 'q')) {
            std::cout << "Invalid choice!\n";
        } else {
            valid = true;
        }
    } while (!valid);
    return choice;
}

void menu::loop() {
    active = true;
    ++nesting_level;
    while (active) {
        print_title(title);
        char choice = read_choice();
        if (choice == 'q') {
            --nesting_level;
            active = false;
        } else {
            items[choice].action();
        }
    }
}
~/programy_cpp/linked_list ❯ cat main.cpp                                                                                                             13:07:41
#include <iostream>
/*#include <string>*/
/*#include "linked_list.h"*/
#include "menu.h"

void display_sth() {
    std::cout << "test\n";
}

int main() {
    menu_items main_menu_items;
    main_menu_items.emplace_back("test", menu::noop);
    main_menu_items.emplace_back("display_sth", display_sth);
    menu main_menu{"Main menu", main_menu_items};
    main_menu.loop();
    return 0;
}
~/programy_cpp/linked_list ❯ ./main                                                                                                                   13:07:47
*************
* Main menu *
*************
What do you want to do?
0) test
1) display_sth
q) Quit
Your choice: 1
/usr/lib/gcc/x86_64-pc-linux-gnu/14/include/g++-v14/bits/stl_vector.h:1130: std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::operator[](size_type) [with _Tp = menu_item; _Alloc = std::allocator<menu_item>; reference = menu_item&; size_type = long unsigned int]: Assertion '__n < this->size()' failed.
zsh: IOT instruction (core dumped)  ./main
~/programy_cpp/linked_list ❯ ./main                                                                                                             ✘ IOT 13:07:51
*************
* Main menu *
*************
What do you want to do?
0) test
1) display_sth
q) Quit
Your choice: 0
/usr/lib/gcc/x86_64-pc-linux-gnu/14/include/g++-v14/bits/stl_vector.h:1130: std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::operator[](size_type) [with _Tp = menu_item; _Alloc = std::allocator<menu_item>; reference = menu_item&; size_type = long unsigned int]: Assertion '__n < this->size()' failed.
zsh: IOT instruction (core dumped)  ./main
~/programy_cpp/linked_list ❯ ./main                                                                                                             ✘ IOT 13:07:55
*************
* Main menu *
*************
What do you want to do?
0) test
1) display_sth
q) Quit
Your choice: q

1 odpowiedź

+1 głos
odpowiedź 23 lutego przez adrian17 Mentor (354,120 p.)
wybrane 23 lutego przez whiteman808
 
Najlepsza

Jak ręcznie kompilujesz na linuxie, to na przyszłość kompiluj z `-g -fsanitize=address`, będziesz mieć dokładniejsze informacje gdzie się posypał.

A błąd masz tutaj:

items[choice].action();

Bo 'choice' jest znakiem '1', co jest czym innym od indeksu 1, więc wychodzisz poza tablicę.

komentarz 23 lutego przez adrian17 Mentor (354,120 p.)
Uwaga na boku: na oko w tym przypadku nie ma potrzeby definiować operator=, domyślnie wygenerowany zrobi to samo.
komentarz 23 lutego przez whiteman808 Gaduła (4,660 p.)
Dziękuję za pomoc :-)

Podobne pytania

0 głosów
1 odpowiedź 1,151 wizyt
pytanie zadane 27 stycznia 2018 w C i C++ przez Jakub 0 Pasjonat (23,120 p.)
0 głosów
1 odpowiedź 144 wizyt
pytanie zadane 13 maja 2017 w C i C++ przez niezalogowany
+1 głos
1 odpowiedź 203 wizyt

93,427 zapytań

142,421 odpowiedzi

322,649 komentarzy

62,787 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

VMware Cloud PRO - przenieś swoją infrastrukturę IT do chmury
...