Std :: allocator < T & gt ;: разрешено ли построение на нераспределенной памяти на C ++? [Дубликат]

Željko Jelić спросил: 28 апреля 2018 в 08:26 в: c++

У этого вопроса уже есть ответ:

  • What is the purpose of allocating a specific amount of memory for arrays in C++? 5 ответов

Итак, я относительно новичок в C ++, и я недавно столкнулся с std::allocator класс. Я понимаю, что это мощный инструмент, используемый при создании vector s, list s, deque и т. Д., И я пытаюсь узнать больше об этом . Одна вещь, которая меня смущает, такова:

Например, если мы определим некоторый allocator<int>, обозначенный как alloc, и мы используем его для выделения n в памяти с помощью auto const b = a.allocate(n), где b - это указатель на первый элемент int в выделенной памяти, тогда один также обязан создайте выделенную память, чтобы фактически получить к ней доступ, правильно? Если мы введем некоторый итерационный указатель auto e=b, то конструкцию можно выполнить с помощью alloc.construct(e++,int_obj), где int_obj является некоторым инициализированным пользователем объектом типа int. Это все хорошо и ручно, если общий объем вызовов construct меньше n. Тем не менее, я не совсем уверен, что произойдет, когда количество пользовательских вызовов construct превышает n. Сначала я ожидал сообщения о предупреждении или ошибке, чтобы задрать его уродливую голову, однако ничего не произошло. В качестве простого примера здесь приведен код, который я пытался запустить:

int n{ 0 };                            // Size of the array is initialized to 0.
cin >> n;                              // User reads in the size.
allocator<int> alloc;                  // 'alloc' is an object that can allocate ints.
auto const b = alloc.allocate(n);      // Pointer to the beginning of the array. 
auto e = b;                            // Moving iterator that will point to the end of the arrayfor (int i = 0;i != 10;++i)
    alloc.construct(e++, i);           // We start constructing 10 elements in the array, regardless of the size n, which can in principle be less than 10.
for (auto i = b;i != e;++i)
    cout << *i << "\t";

Изначально я запускаю этот код для n=1, и все работает хорошо; он печатает цифры от 0 до 9, хотя я выделил место только для одной цифры. Это уже красный флаг, верно? Затем я меняю n на 2, и программа прерывается после печати цифры номер четыре, что больше того, что я ожидал.

Что я заключил из этого поведения, что попытка создания памяти, еще не выделенной с помощью std::allocator, не определена и непредсказуема, и как таковое следует избегать (что очевидно для начала). Но это кажется чрезвычайно опасной ловушкой, и я хотел знать, есть ли встроенный обходной путь в C ++, который всегда будет препятствовать пользователю при попытке построить нераспределенную память.

1 ответ

Есть решение
Useless ответил: 28 апреля 2018 в 09:48

Но это кажется чрезвычайно опасным ловушкой,

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

Если вам нужно обрабатывать необработанную память напрямую, обычно лучше писать собственный контейнер, который вы можете протестировать на аналогичный стандарт, вместо того, чтобы чередовать ручное управление памятью с остальной частью вашей логики программы.

, и я хотел знать, есть ли какое-либо встроенное обходное решение в C ++ который всегда будет препятствовать пользователю при попытке создать нераспределенную память.

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

Однако есть много инструментов, которые помогут вам протестировать и диагностировать эти ошибки, для Пример:

  • У компиляторов clang и gcc есть дезинфицирующие средства для адресов, которые скомпилируют эти проверки в вашей программе (это необязательный компонент компилятора, а не часть языка).
  • valgrind - это внешняя программа, чей инструмент по умолчанию (memcheck) запускает вашу настоящую программу для поиска этих ошибок. Он медленный, но он используется для тестирования или отладки, а не для живых программ.