Может кто-нибудь объяснить, почему указатели не инициализируются NULL
?
Пример:
void test(){
char *buf;
if (!buf)
// whatever
}
Программа не будет входить в if, потому что buf
не является нулем.
Я хотел бы знать, зачем и в каком случае нам нужна переменная с мусором, особенно указатели, обращающиеся к мусору в памяти?
c++
memory
pointers
initialization
Джонатан
источник
источник
Ответы:
Мы все понимаем, что указатель (и другие типы POD) следует инициализировать.
Тогда возникает вопрос: «Кто должен их инициализировать».
Что ж, в основном есть два метода:
Предположим, что компилятор инициализировал любую переменную, явно не инициализированную разработчиком. Затем мы сталкиваемся с ситуациями, когда инициализация переменной была нетривиальной, а причина, по которой разработчик не сделал этого в точке объявления, заключалась в том, что ему / ей нужно было выполнить некоторую операцию, а затем назначить.
Итак, теперь у нас есть ситуация, когда компилятор добавил в код дополнительную инструкцию, которая инициализирует переменную значением NULL, а затем добавляется код разработчика для правильной инициализации. Или при других условиях переменная потенциально никогда не используется. Многие разработчики C ++ кричали бы о фоле в обоих случаях за счет этой дополнительной инструкции.
Дело не только в времени. Но также и космос. Есть много сред, в которых оба ресурса в цене, и разработчики не хотят отказываться от них.
НО : Вы можете имитировать эффект принудительной инициализации. Большинство компиляторов предупредит вас о неинициализированных переменных. Поэтому я всегда устанавливаю максимально возможный уровень предупреждения. Затем скажите компилятору рассматривать все предупреждения как ошибки. В этих условиях большинство компиляторов будут генерировать ошибку для переменных, которые не инициализированы, но используются, и, таким образом, предотвратят создание кода.
источник
Цитата Бьярна Страуструпа в TC ++ PL (Special Edition, стр.22):
источник
D
есть. Если вы не хотите инициализации, используйте этот синтаксисfloat f = void;
илиint* ptr = void;
. Теперь он инициализируется по умолчанию, но если вам действительно нужно, вы можете остановить компилятор от этого.Потому что инициализация требует времени. А в C ++ самое первое, что вы должны сделать с любой переменной, - это явно инициализировать ее:
или:
или:
источник
Потому что один из девизов C ++:
Вы не платите за то, что не используете
Именно по этой причине,
operator[]
вvector
классе не проверяет , если индекс выходит за пределы, например.источник
По историческим причинам, в основном потому, что именно так это делается в C. Почему это делается так в C, это другой вопрос, но я думаю, что принцип нулевых накладных расходов каким-то образом был задействован в этом дизайнерском решении.
источник
Кроме того, у нас есть предупреждение, когда вы его взорвете: «возможно, используется до присвоения значения» или аналогичные слова в зависимости от вашего компилятора.
Вы ведь компилируете с предупреждениями?
источник
Существует исчезающе мало ситуаций, в которых когда-либо имеет смысл неинициализировать переменную, а инициализация по умолчанию имеет небольшие затраты, так зачем это делать?
C ++ - это не C89. Черт, даже C не C89. Вы можете смешивать объявления и код, поэтому вам следует отложить объявление до тех пор, пока у вас не будет подходящего значения для инициализации.
источник
Указатель - это просто еще один тип. Если вы создаете
int
,char
или любую другую POD типа он не инициализирован к нулю, так почему бы указатель? Это можно считать ненужными накладными расходами для тех, кто пишет такую программу.Если вы знаете, что собираетесь инициализировать его, почему программа должна нести затраты при первом создании
pBuf
в начале метода? Это принцип нулевых накладных расходов.источник
Если вам нужен указатель, который всегда инициализируется значением NULL, вы можете использовать шаблон C ++ для имитации этой функции:
источник
Foo *a
, что вы используетеInitializedPointer<Foo> a
- чисто академическое упражнение, так какFoo *a=0
меньше набора текста. Однако приведенный выше код очень полезен с образовательной точки зрения. С небольшой модификацией (для "размещения" ctor / dtor и операций присваивания) его можно было легко расширить до различных типов интеллектуальных указателей, включая указатели с ограниченными областями (которые освобождаются от деструктора) и указатели со счетчиком ссылок, добавив inc / dec, когда m_pPointer установлен или очищен.Обратите внимание, что статические данные инициализируются значением 0 (если не указано иное).
И да, вы всегда должны объявлять свои переменные как можно позже и с начальным значением. Код вроде
должен вызывать тревогу, когда вы его читаете. Я не знаю, можно ли убедить кого-нибудь из линтов придраться к нему, поскольку это на 100% законно.
источник
Другая возможная причина заключается в том, что указателям во время компоновки присваивается адрес, но за косвенную адресацию / разыменование указателя несет ответственность программист. Обычно компилятору все равно, но ответственность за управление указателями и обеспечение отсутствия утечки памяти перекладывается на программиста.
На самом деле, в двух словах, они инициализируются в том смысле, что во время компоновки переменной-указателю присваивается адрес. В приведенном выше примере кода это гарантированно приведет к сбою или генерации SIGSEGV.
Ради здравого смысла всегда инициализируйте указатели на NULL, таким образом, если какая-либо попытка разыменовать его без
malloc
илиnew
укажет программисту причину неправильного поведения программы.Надеюсь, это поможет и имеет смысл,
источник
Что ж, если бы C ++ действительно инициализировал указатели, то у C ++, жалующегося на то, что «C ++ медленнее, чем C», было бы что-то реальное, за что можно было бы держаться;
источник
C ++ происходит из фона C - и отсюда есть несколько причин:
C, даже больше, чем C ++, является заменой языка ассемблера. Он не делает того, о чем вы не говорите. Поэтому: Если вы хотите NULL - сделайте это!
Кроме того, если вы обнуляете вещи на голом металлическом языке, таком как C, автоматически возникают вопросы согласованности: если вы что-то распределяете - должно ли оно быть обнулено автоматически? А как насчет структуры, созданной в стеке? все байты должны быть обнулены? А как насчет глобальных переменных? как насчет утверждения типа "(* 0x18);" Значит ли это, что позиция памяти 0x18 должна быть обнулена?
источник
calloc()
.О каких указателях вы говорите?
Для обеспечения безопасности исключений, всегда используйте
auto_ptr
,shared_ptr
,weak_ptr
и другие их варианты.Отличительной чертой хорошего кода является тот, в котором нет ни одного обращения к
delete
.источник
auto_ptr
и заменяйтеunique_ptr
.О, парень. Реальный ответ заключается в том, что легко обнулить память, которая является базовой инициализацией, скажем, указателя. Что также не имеет ничего общего с инициализацией самого объекта.
Учитывая предупреждения, которые большинство компиляторов выдают на самом высоком уровне, я не могу представить себе программирование на высшем уровне и рассмотрение их как ошибок. Поскольку их включение никогда не спасло меня, даже одна ошибка в огромном количестве созданного кода, я не могу рекомендовать это.
источник
NULL
, инициализирует его , что это так же ошибка.