С ++ поведение, которое я не понимаю - PullRequest
0 голосов
/ 12 января 2020

Мои друзья и я играли с языком C ++. При этом мы столкнулись с чем-то, чего не могли понять.

Вот код:

#include <vector>
#include <iostream>

void print(std::vector<char> const &input)
{
    std::cout << input.size();
    for (int i = 0; i < input.size(); i++)
    {
        std::cout << input.at(i) << " - ";
    }

}

int main()
{
    char cha = 'A';
    char chb = 'B';
    char * pcha = &cha;
    char * pchb = &chb;
    try
    {
        std::vector<char> a = {pcha, pchb};
        //std::vector<char> a = {pchb, pcha};
        print(a);

    }
    catch(std::exception e)
    {
        std::cout << e.what();
    }
}

Вывод этого кода:

A

Когда я закомментирую эту первую строку, попробуйте блок и раскомментируем вторую строку, что приводит к следующему:

try
{
    // std::vector<char> a = {pcha, pchb};
    std::vector<char> a = {pchb, pcha};
    print(a); 
}

Вывод становится:

std: исключение

Я подумал, что, возможно, это происходит из-за различных отступов и выравниваний объявленных переменных (char, char *), но до сих пор не понял. Вы можете найти код здесь , чтобы поиграть. Заранее спасибо.

Ответы [ 2 ]

6 голосов
/ 12 января 2020
std::vector<char> a = {pcha, pchb};

Здесь вы используете конструктор вектора, который принимает два итератора в диапазон. Если конечный итератор не доступен с самого начала, поведение программы не определено. Ваши два указателя не являются итераторами одного и того же диапазона (т. Е. Элементами массива), поэтому один из них недоступен для другого. Поэтому поведение программы не определено.

Это будет правильно:

std::vector<char> a = {cha, chb}; // uses initializer_list constructor

// or
char arr[] {cha, chb};
char * pcha = std::begin(arr);
char * pchb = std::end(arr);
std::vector<char> a = {pcha, pchb}; // uses the iterator constructor
2 голосов
/ 12 января 2020

@ ответ eerorika объясняет вашу ошибку.

Однако я хотел бы отговорить вас и других читателей от использования второй части его (?) Исправленного фрагмента кода - не потому, что он неправильный, но потому что это проблематично c практика кодирования:

  1. Я принимаю предложение Николаса Джоссутиса о попытке равномерно инициализировать переменные с помощью фигурных скобок и без равных с тех пор (например, mytype myvar {my_initializer};) .
  2. Отдельно стоящие указатели - опасные звери. Старайтесь вообще избегать их или минимизируйте их существование там, где они вам действительно нужны. В конце концов, у вас возник соблазн использовать эти указатели ненадлежащим образом ... так что,
    char arr[] {cha, chb};
    std::vector<char> a = {std::begin(arr), std::end(arr)};
    
  3. Не создавайте фиктивный контейнер только для того, чтобы создать тот, который вам действительно нужен. Просто придерживайтесь первой строки в предложении @ eerorika (без знака равенства):
    std::vector<char> a {cha, chb}; 
    
  4. На самом деле, если вам это действительно не нужно - вы, вероятно, даже не хотите создавать контейнер переменной длины. Так что, возможно, просто
    std::array<char, 2> a {cha, chb}; 
    
    или с выводом аргумента шаблона C ++ 17:
    std::array a {cha, chb}; 
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...