Не могу найти ошибку в этой маленькой программе - PullRequest
0 голосов
/ 02 декабря 2018

У меня есть очень специфическая проблема, связанная с C ++ в книге, которую я сейчас изучаю.Книга называется «Принципы и практики программирования с использованием C ++», и автор является самим ее создателем.

Моя проблема в основном в том, что книга просит вас найти серьезную ошибку, которая есть в этой очень маленькой программе (для практикиконечно), но я не уверен, является ли ошибка ошибкой или даже считается ошибкой.

Вот небольшой фрагмент кода:

template<typename Iterator>
Iterator high(Iterator first, Iterator last)
{
    Iterator high = first;
    for (Iterator p = first; p != last; ++p) {
        if (*high < *p) high = p;
    }

    return high;
}

double* get_from_jack(int* count)
{
    *count = 3;
    return new double[3]{ 1.1, 2.2, 3.3 };
}

vector<double>* get_from_jill()
{
    return new vector<double>{ 1.1, 2.2, 3.3 };
}

void fct()
{
    int jack_count = 0;
    double* jack_data = get_from_jack(&jack_count);
    vector<double>* jill_data = get_from_jill();

    double* jack_high = high(jack_data, jack_data + jack_count);
    vector<double>& v = *jill_data;
    double* jill_high = high(&v[0], &v[0] + v.size());

    cout << "Jack high: " << *jack_high << endl
        << "Jill high: " << *jill_high << endl;

    delete[] jack_data;
    delete jill_data;
}

«Ошибка», которую я обнаружил, заключается в том, что вы можете передать два произвольных адреса памяти в функцию «high», и она не будет работать правильно.Итак, мой вопрос здесь, я прав или я что-то упускаю?Я все еще изучаю C ++ и программирование, так что это поможет моим знаниям, я ничего больше не получу от этого, кроме знаний.

Редактировать: Как утверждают некоторые пользователи, это ужасный код, но он не долженТрудно понять, что это были намерения автора.Метод обучения в книге - медленно переходить от неаккуратного кода к гораздо лучшему коду, используя более продвинутые методы.

Ответы [ 2 ]

0 голосов
/ 02 декабря 2018

Наиболее очевидная ошибка - если массив или вектор имеют нулевой размер. В этом случае первая строка функции возвращает первую, которая при разыменовании не определена.Лучше возвращать последний, когда первый == последний.Это хорошо определено и является стандартной практикой для массивов и векторов, но вы должны проверить это и не разыменовывать его.

template<typename Iterator>
Iterator high(Iterator first, Iterator last)
{
    if (first == last) return last;

    Iterator high = first;
    for (Iterator p = first; p != last; ++p) {
        if (*high < *p) high = p;
    }

    return high;
}

Эта строка не определена для векторов нулевого размера - выне может взять нулевой элемент пустого вектора:

double* jill_high = high(&v[0], &v[0] + v.size());

Вместо этого должно быть так:

std::vector<double>::iterator jill_high = high(v.begin(), v.end());

И тогда вы должны проверить, если результатдля массива jack_data + jack_count для массива и v.end() для вектора, поскольку вы не можете разыменовать ни один из них.Вместо этого вы можете распечатать «N / A» или что-то подобное.

0 голосов
/ 02 декабря 2018

«Ошибка», которую я обнаружил, заключается в том, что вы можете передать два случайных адреса памяти в функцию high, и она не будет работать правильно.

Каковы ваши ожидания в этомcase?

В C ++ сравнение указателей хорошо определено только тогда, когда указатели ссылаются на элементы одного и того же массива (включая указатель на один последний элемент).В противном случае это неопределенное поведение .Для неопределенного поведения Стандарт C ++ не требует какого-либо особого поведения, поэтому undefined .

...