Как продемонстрировать ошибку памяти с помощью массивов в C++

Я пытаюсь думать о методе, демонстрирующем своего рода ошибку памяти с помощью Массивов и C++, который трудно обнаружить. Цель состоит в том, чтобы мотивировать использование вектора STL <> в сочетании с итераторами.

Править: Принятый ответ является ответом, я раньше объяснял преимущества / недостатки. Я также использовал: это

6
задан Community 23 May 2017 в 12:26
поделиться

8 ответов

Утечка памяти? IMO, вектор в сочетании с итераторами не особо защищает вас от ошибок, таких как выход за пределы или вообще использование недействительного итератора (если у вас нет VC ++ с отладкой итератора); скорее это удобно, потому что он реализует для вас динамически изменяемый размер и заботится об управлении памятью (NB! помогает сделать ваш код более безопасным для исключений).

void foo(const char* zzz)
{
    int* arr = new int[size];
    std::string s = zzz;
    //...
    delete[] arr;
}

Вышеупомянутая информация может просочиться в случае возникновения исключения (например, при создании строки). Не с вектором.

Vector также упрощает рассуждения о коде из-за его семантики значений.

int* arr = new int[size];
int* second_ref = arr;
//...
delete [] arr; 
arr = 0; //play it safe :)

//...
second_ref[x] = y;
//...
delete [] second_ref;

Но, возможно, вектор автоматически не удовлетворяет 100% случаев использования динамического массива. (Например, есть также boost :: shared_array и будущий std :: unique_ptr )

6
ответ дан 8 December 2019 в 03:26
поделиться

Я думаю, что полезность std::vector действительно проявляется, когда вам нужны динамические массивы.

Сделайте один пример с использованием std::vector. Затем один пример с использованием массива для перераспределения. Я думаю, это говорит само за себя.

4
ответ дан 8 December 2019 в 03:26
поделиться

Я думаю, что простота использования векторов вместо динамических массивов уже убедительна.

  1. Вам не нужно помнить, чтобы стереть свою память ... что не так просто, поскольку попытки удалить ее могут быть обойдены исключениями и прочим.
  2. Если вы хотите создавать динамические массивы самостоятельно, самый безопасный способ сделать это на C ++ - обернуть их в класс и использовать RAII . Но векторы делают это за вас. Собственно, в этом-то и дело.
  3. Изменение размера сделано за вас.
  4. Если вам нужно поддерживать произвольные типы, вам не нужно выполнять дополнительную работу.
  5. Предоставляется множество алгоритмов, предназначенных для работы с контейнерами, как включенными, так и другими пользователями.
  6. Вы по-прежнему можете использовать функции, которым требуются массивы, передав при необходимости базовый массив вектора; Стандарт гарантирует непрерывность памяти, за исключением vector (Google говорит по состоянию на 2003 год, см. 23.2.4./1 спецификации).
  7. Использование массива самостоятельно, вероятно, является плохой практикой в ​​целом, так как вы будете заново изобретать колесо ... и ваша реализация почти наверняка будет намного хуже, чем существующая ... и сложнее для использования другими людьми, поскольку они знают о векторе , но не о вашей странности.

С динамическим массивом вам нужно самостоятельно отслеживать размер, увеличивать его, когда вы хотите вставить новые элементы, и удалять, когда он больше не нужен ... это дополнительная работа. Ой. и предупреждение: vector - это грязный тухлый взлом и классический пример преждевременной оптимизации.

3
ответ дан 8 December 2019 в 03:26
поделиться
void Fn()
{
    int *p = new int[256];
    if ( p != NULL )
    {
        if ( !InitIntArray( p, 256 ) )
        {
              // Log error
              return;
        }
        delete[] p;
    }
}

Вы не поверите, как часто я это вижу. Классический пример того, где любая форма RAII полезна ...

3
ответ дан 8 December 2019 в 03:26
поделиться

Неправильное сопряжение new/delete и new[]/delete[].

Например, использование:

int *array = new int[5];
delete array;

вместо:

int *array = new int[5];
delete [] array;

И хотя стандарт c++ не позволяет этого, некоторые компиляторы поддерживают выделение массива стеком:

int stack_allocated_buffer[size_at_runtime];

Это может быть непредусмотренным побочным эффектом правил скопирования (например, константа, затененная переменной-членом)... и это работает, пока кто-то не передаст 'size_at_runtime' слишком большим и не снесет стек. Тогда возникают отстойные ошибки.

8
ответ дан 8 December 2019 в 03:26
поделиться

Один очевидный:

for (i = 0; i < NUMBER_OF_ELEMENTS; ++i)
    destination_array[i] = whatever(i);

против

for (i = 0; i < NUMBER_OF_ELEMENTS; ++i)
    destination_vector.push_back(whatever(i));

указывая на то, что вы знаете, что второе работает, но работает ли первое, зависит от того, как был определен destination_array.

3
ответ дан 8 December 2019 в 03:26
поделиться

Почему бы вам не мотивировать это на основе алгоритмов, которые предоставляет STL?

2
ответ дан 8 December 2019 в 03:26
поделиться

В сыром массиве operator[] (если можно так выразиться) подвержен проблеме index-out-of-bound. С вектором это не так (есть, по крайней мере, исключение во время выполнения).

Извините, я недостаточно внимательно прочитал вопрос. index-out-of-bound - это проблема, но не ошибка памяти.

0
ответ дан 8 December 2019 в 03:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: