Используйте calloc
для распределений с нулевым заполнением, но только тогда, когда заполнение нулями действительно необходимо.
Вы всегда должны использовать calloc(count,size)
вместо buff=malloc(total_size); memset(buff,0,total_size)
.
Призыв к нулю-memset
- это ключ. И malloc
, и calloc
транслируются в вызовы ОС, которые выполняют множество оптимизаций, по возможности используют аппаратные уловки и т. Д. Но ОС мало что может сделать с memset
.
С другой стороны, когда вам нужно обнулить выделенную память? Единственное распространенное использование - это элементы произвольной длины с нулевым концом, такие как C-строки. Если это так, конечно, используйте calloc
.
Но если вы выделяете структуры, в которых элементы либо фиксированной длины, либо несут с собой длину элементов произвольного размера (например, строки и векторы C ++), заполнение нулями вообще бесполезно, и если вы попытаетесь полагаться на на нем это может привести к хитрым ошибкам.
Предположим, вы написали свой настраиваемый связанный список и решили пропустить обнуление указателя на следующий узел, выделив память для узла с помощью calloc
. Он работает нормально, затем кто-то использует его с настраиваемым размещением new, которое не заполняется нулями. Проблема в том, что иногда он будет заполнен нулями и может пройти все обычные тесты, поступить в производство, и там он выйдет из строя, иногда выйдет из строя, ужасная неповторимая ошибка.
Для целей отладки заполнение нулями обычно тоже не очень хорошо. 0 слишком распространено, вы редко можете написать что-то вроде assert(size);
, потому что обычно это действительное значение, вы обрабатываете его с помощью if(!size)
, а не с помощью утверждений. В отладчике это тоже не бросается в глаза, в памяти обычно везде нули. Лучше всего избегать беззнаковых типов для длин (подписанные длины могут быть полезны для обработки ошибок во время выполнения, а также для некоторых наиболее распространенных проверок переполнения). Итак, хотя buff=malloc(total_size); memset(buff,0,total_size)
следует избегать, следующее нормально:
const signed char UNINIT_MEM=MY_SENTINEL_VALUE;
buff=malloc(total_size);
#if DEBUG_MEMORY
memset(buff,UNINIT_MEM,total_size);
#endif
В режиме отладки библиотека времени выполнения или даже ОС иногда делают это за вас, например, проверьте этот отличный пост о специальных дозорных значениях VC ++.
person
Mike Tyukanov
schedule
22.12.2016
calloc()
? - person Sourav Ghosh   schedule 21.12.2016calloc
сломать любую программу, которая нормально работает сmalloc
? Каждый, кто используетmalloc
, должен знать, что он не может полагаться на содержимое буфера. Если это все нули, это всего лишь один из возможных результатов случайного содержимого. - person Gerhardh   schedule 21.12.2016C
, потому что вопрос касаетсяC
функций. Я хорошо осведомлен о передовых методах управления памятью C ++, но есть один случай, когда я чувствуюmalloc
лучший способ выделить память: когда мне нужно выделить буфер фиксированного размера, который инкапсулирован в одном из моих классов. - person Violet Giraffe   schedule 21.12.2016malloc
. Я просто использую::operator new
, если мне действительно нужно. - person StoryTeller - Unslander Monica   schedule 21.12.2016std::unique_ptr<T[]>
я бы пошел по пути. Теперь у вас есть встроенное управление памятью. - person NathanOliver   schedule 21.12.2016std::unique_ptr
просто связывает это удаление с областью действия указателей, поэтому вам не нужно об этом помнить.std::unique_ptr
со средством удаления по умолчанию должно быть столь же эффективным, как и выполнение его самостоятельно, с тем преимуществом, что на самом деле нельзя ошибиться. - person NathanOliver   schedule 21.12.2016class unique_ptr {T* _ptr};
- person Violet Giraffe   schedule 21.12.2016p = make_unique<...>(...);
необходимо сначала выполнить нулевую проверкуp
, даже если вы уже статически знаете, что оно равно нулю. Более того, передача уникальных указателей через вызовы функций уступает Itanium ABI, потому что объект должен помещаться в стек, а необработанный указатель передается в регистре. (Это ошибка реализации, а не ошибка дизайна, но все же.) - person Kerrek SB   schedule 21.12.2016delete[]
, то это даже не увеличивает размер указателя. В gccsizeof(std::unique_ptr<int[]>)
это8
, который имеет тот же размер, что и одиночный указатель (64 бита). - person NathanOliver   schedule 21.12.2016