Есть ли способ сбросить getopt для неглобального использования?

При попытке использовать getopt несколько раз ошибка, которую я получаю в valgrind, равна Invalid read of size 1. Ошибка возникает только тогда, когда вы делаете что-то вроде этого:

ls -a -b
ls -a -b

Поэтому я предполагаю, что проблема связана с повторным использованием функций getopt.

Command.h

class Command {
    protected:
            // for use in getopt
        int c = 0;
            // name of command
        char* name;
    public:
        Command(const char* nname) : name((char*)nname) { }
        virtual ~Command() { };
        virtual void process_args(int argc, char* argv[]) = 0;
        virtual char* get_name() const {
            return name;
        }
};

ls.h - это просто это, заключенное в класс:

class ls : public Command {
    public:
        ls() : Command("ls") { }
        ~ls() { }
        void process_args(int input_argc, char* input_argv[]) {
            int verbose_flag = 0;

            struct option long_options[] =
            {
                    /* These options set a flag. */
                    {"verbose", no_argument,       &verbose_flag, 1},
                    {"brief",   no_argument,       &verbose_flag, 0},
                    /* These options don't set a flag.
                        We distinguish them by their indices. */
                    {"add",     no_argument,       0, 'a'},
                    {"append",  no_argument,       0, 'b'},
                    {"delete",  required_argument, 0, 'd'},
                    {"create",  required_argument, 0, 'c'},
                    {"file",    required_argument, 0, 'f'},
                    {0, 0, 0, 0}
            };

            while (1) {
                      // removed static and moved struct outside
                      // everything else is the same
                    }
        }
};

main.cpp

std::vector<std::unique_ptr<Command>> commands;
commands.push_back(std::unique_ptr<Command>(new ls()));
commands.push_back(std::unique_ptr<Command>(new shibe()));

while (true) {
    std::string input;
    std::getline(std::cin, input);
    if (input == "quit")
        break;
    std::istringstream iss(input);
    std::vector<std::string> args;
    std::copy(std::istream_iterator<std::string>(iss), std::istream_iterator<std::string>(), std::back_inserter(args));
    int input_argc = args.size();
    char* input_argv[input_argc];
    for (int i = 0; i < args.size(); i++) {
        input_argv[i] = (char*)args[i].c_str();
    }

    for (int i = 0; i < commands.size(); i++) {
        if (strcmp(input_argv[0], commands[i]->get_name()) == 0) {
            commands[i]->process_args(input_argc, input_argv);
            break;
        }
    }
}

Вывод Valgrind:

ls -a -b
--30624-- REDIR: 0x375e8812d0 (strlen) redirected to 0x480155c (_vgnU_ifunc_wrap                                                                                                 per)
--30624-- REDIR: 0x375e87f810 (__GI_strchr) redirected to 0x4a07b30 (__GI_strchr                                                                                                 )
option -a
option -b
ls -a -b
==30624== Invalid read of size 1
==30624==    at 0x375E8CDFDC: _getopt_internal_r (in /lib64/libc-2.12.so)
==30624==    by 0x375E8CF1EA: _getopt_internal (in /lib64/libc-2.12.so)
==30624==    by 0x375E8CF2D2: getopt_long (in /lib64/libc-2.12.so)
==30624==    by 0x401E1C: ls::process_args(int, char**) (ls.h:31)
==30624==    by 0x4019CB: main (main.cpp:36)
==30624==  Address 0x513e5da is 26 bytes inside a block of size 27 free'd
==30624==    at 0x4A05FD6: operator delete(void*) (vg_replace_malloc.c:480)
==30624==    by 0x4CCADFE: std::basic_string<char, std::char_traits<char>, std::                                                                                                 allocator<char> >::~basic_string() (basic_string.h:538)
==30624==    by 0x403AA5: void std::_Destroy<std::string>(std::string*) (stl_con                                                                                                 struct.h:93)
==30624==    by 0x403855: void std::_Destroy_aux<false>::__destroy<std::string*>                                                                                                 (std::string*, std::string*) (stl_construct.h:103)
==30624==    by 0x403466: void std::_Destroy<std::string*>(std::string*, std::st                                                                                                 ring*) (stl_construct.h:126)
==30624==    by 0x402DE6: void std::_Destroy<std::string*, std::string>(std::str                                                                                                 ing*, std::string*, std::allocator<std::string>&) (stl_construct.h:151)
==30624==    by 0x402878: std::vector<std::string, std::allocator<std::string> >                                                                                                 ::~vector() (stl_vector.h:415)
==30624==    by 0x401A03: main (main.cpp:26)
==30624==
--30624-- REDIR: 0x375e8846b0 (mempcpy) redirected to 0x4a09f80 (mempcpy)
non-option input_argv-elements: s b
quit
--30624-- REDIR: 0x375e87b6d0 (free) redirected to 0x4a06369 (free)
==30624==
==30624== HEAP SUMMARY:
==30624==     in use at exit: 0 bytes in 0 blocks
==30624==   total heap usage: 36 allocs, 36 frees, 916 bytes allocated
==30624==
==30624== All heap blocks were freed -- no leaks are possible
==30624==
==30624== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6)
==30624==

person Community    schedule 12.11.2013    source источник
comment
Похоже, вы просто установили optind на 1   -  person uk4321    schedule 13.11.2013


Ответы (1)


Справочная страница Linux на getopt() поясняет, как сбросить getopt() (который к сожалению, использует ряд глобальных переменных для связи с вызывающим абонентом и поддержания состояния):

Переменная optind - это индекс следующего элемента, который будет обрабатываться в argv. Система инициализирует это значение до 1. Вызывающий может сбросить его до 1, чтобы перезапустить сканирование того же argv или при сканировании нового вектора аргументов.

person Michael Burr    schedule 12.11.2013
comment
Другими словами, optind=1; - person philn; 03.08.2021