Как передать всю коллекцию (char **) аргументов командной строки только для чтения в С++?

Предположим, у меня есть такая программа:

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

// Takes values and outputs a string vector.
std::vector<std::string> foo(const int argc, char* args[]) {
    std::vector<std::string> strings;
    for (int i = 0; i < argc; i++)
        strings.push_back(args[i]);
    return strings;
}

int main(int argc, char *args[]) {

    std::vector<std::string> strings = foo(argc, args);

    for (unsigned int i = 0; i < strings.size(); i++)
        std::cout << strings[i] << std::endl;

    return 0;
}

Суть в том, что я пытаюсь передать аргумент char** функции main() другой функции или классу. (Я понимаю, что есть лучшие способы добиться того, что делает вышеуказанная программа, мой вопрос касается передачи аргументов char ** только для чтения).

Вопросы:

  1. Я обнаружил, что не могу сделать второй аргумент foo() константным, как первый. Почему это? Символ** не может быть преобразован в константный символ**?
  2. Я хочу передать этот аргумент как «только для чтения». Я не уверен, как это сделать, если бы это была строка, которую я бы передал через ссылку на константу, но я не уверен, как это сделать с указателями?

person Jaymaican    schedule 11.02.2019    source источник
comment
вопрос был бы лучше, если бы вы включили то, что пробовали, и сообщение об ошибке, которое вы получили   -  person 463035818_is_not_a_number    schedule 11.02.2019
comment
Немного OT, но если вам нужен вектор ваших аргументов командной строки, вы можете создать его так: std::vector<std::string> args(argv+1, argv+argc); (argv+1, чтобы пропустить имя программы)   -  person Ted Lyngmo    schedule 11.02.2019


Ответы (1)


Я обнаружил, что не могу сделать второй аргумент foo() константным, как первый. Почему это? Символ** не может быть преобразован в константный символ**?

Если бы это было разрешено, вы, вероятно, нарушили бы константную правильность. Учти это

char const *a = "literl";
char *b = nullptr;
char const **c = &b; // This is not allowed in C++. Like your code.
*c = a; // The qualifications match, but now it's b that points at a literal.
*b = 'L'; // Modifying a string literal! Oops!

Так что есть веская причина, чтобы запретить это, как написано. Но это не значит, что вы вообще не можете делать то, что хотите. Квалификационные преобразования возможны, если они более строгие. Ну в любом случае суть.

Я хочу передать этот аргумент как «только для чтения». Я не уверен, как это сделать, если бы это была строка, которую я бы передал через ссылку на константу, но я не уверен, как это сделать с указателями?

Передайте указатель на const указатель на const char. Лучше напишите это в коде, чтобы объяснить:

                                                         // The const here
std::vector<std::string> foo(int const argc, char const* const args[]) {
    std::vector<std::string> strings;
    for (int i = 0; i < argc; i++)
        strings.push_back(args[i]);
    return strings;
}

Почему это разрешено? Потому что, если мы приравняем его к плохому примеру, с которого я начал, c больше нельзя будет использовать для присвоения b, и поэтому мы не сможем попасть в ошибочное состояние.

person StoryTeller - Unslander Monica    schedule 11.02.2019
comment
Большое спасибо за подробный ответ! Я понимаю, что сейчас это запрещено. Я все еще немного запутался в синтаксисе char const* const args[]. Кажется, я могу заставить const char* const args[] и const char* const* args компилироваться нормально. Я понимаю, что это, вероятно, одно и то же, но я застрял на синтаксисе и на том, какой термин что контролирует. Не могли бы вы очень кратко объяснить каждый компонент char const* const args[] и то, что он делает, чтобы сделать переменную доступной только для чтения? - person Jaymaican; 11.02.2019
comment
@Jaymaican - args не является неизменным ни в одном объявлении. То, что является неизменным, это то, на что он указывает. Итак, *args это const. Мы не можем присвоить ему что-то недопустимое. И **args является константой, как вы, очевидно, хотели. Это имеет больше смысла? - person StoryTeller - Unslander Monica; 11.02.2019
comment
Хорошо, это имеет больше смысла, я думаю, что меня смутило использование const дважды рядом друг с другом. Я не знал, что указатель const на самом деле вещь! - person Jaymaican; 11.02.2019
comment
@Jaymaican - указатель - это объект. Так что его можно объявить константным, как и любой другой объект :) - person StoryTeller - Unslander Monica; 11.02.2019
comment
Теперь становится намного яснее. Один последний вопрос/просьба, который у меня есть, который был бы действительно полезен, — это разбивка синтаксиса char const* const args[]. Я привык ставить const слева от всего и немного запутался в синтаксисе. Не могли бы вы отметить, какой компонент соответствует какой фразе в вашем предложении. Передайте указатель на константный указатель на константный символ. Также это может быть просто мое устройство, но // The const here выстраивается почти посередине двух ключевых слов const: P - person Jaymaican; 11.02.2019
comment
@Jaymaican - char const* const args[] это ровно char const* const *args (я просто не хотел слишком сильно менять ваш пример). Теперь читайте справа налево. args является указателем на константный указатель на константу char. Определитель относится к предмету слева... за исключением случаев, когда там ничего нет. Для согласованности я всегда помещаю его справа, когда это возможно. - person StoryTeller - Unslander Monica; 11.02.2019
comment
Я думаю, что где-то на SO тоже есть вопросы и ответы по этому вопросу. Вы можете просмотреть его, чтобы узнать больше. - person StoryTeller - Unslander Monica; 11.02.2019
comment
Большое спасибо, теперь я полностью понимаю. :) Мне просто синтаксически было непонятно, что [] означает *. - person Jaymaican; 11.02.2019
comment
Вот красивое математическое определение из стандарта разрешенных конверсий (для некоторых стандарт красоты). Проще говоря (для некоторого стандарта простоты): если вы собираетесь добавить const в любом месте, например. char ****, то необходимо также добавить const во всех следующих позициях, кроме последней: char **** -> char *const *** -> char *const *const *const *. - person Arne Vogel; 11.02.2019