Поведение после использования malloc в C ++ - PullRequest
0 голосов
/ 18 сентября 2010

Вызывает ли следующий код неопределенное поведение?Насколько я знаю, мы всегда должны использовать new для создания пользовательских объектов динамически, потому что new в дополнение к malloc также вызывает конструктор.

#include <cstdio>
#include <cstdlib>

struct om
{
    int a;
    void fun()
    {
        a=10;b=10;
    }
    private : int b;

} s1; // structure(om) variable... 


typedef struct om node;

int main()
{
node *s2=(node *)malloc(sizeof(node));
s1.fun();
printf("%d",s2->a);
return 0;
}

Приведенный выше код печатает 0. Это означает, что s2->a автоматически инициализируетсядо 0?Итак, я хочу знать, определено ли поведение программы Implmentation, не определено или хорошо определено?

Ответы [ 5 ]

4 голосов
/ 18 сентября 2010

malloc не гарантирует инициализации памяти, которую он выделяет - если вы хотите, чтобы память была заполнена нулями, используйте calloc.

3 голосов
/ 18 сентября 2010

Приведенный выше код печатает 0. Это означает, что s2-> a автоматически инициализируется равным 0?

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

Насколько я знаю, мы всегда должны использовать new для создания пользовательских объектов динамически, потому что new в дополнение к вызовам mallocконструктор тоже.

Да.malloc не вызывает конструкторы.new делает.При написании кода на C ++ настоятельно рекомендуется всегда предпочитать new вместо malloc (и даже для примитивных типов, а не только для пользовательских).

Вызывает ли следующий код неопределенное поведение?

Я не адвокат по языкам, но я попробую ...

Я думаю, можно сказать, что это хорошо определенное поведение, которое такое неинициализированноепеременные имеют неопределенные значения.Поэтому независимо от значения s2->a оно соответствует стандарту C ++.

1 голос
/ 18 сентября 2010

Поведение не определено. malloc не вызывает конструктор для инициализации памяти. И именно поэтому это самый быстрый способ выделения памяти в C ++

1 голос
/ 18 сентября 2010

Вы интерпретируете часть необработанной памяти (то, что возвращает std::malloc()) как объект (приведение (node*)malloc(...)) и затем получаете доступ к члену на нем (s2->a).На практике вам это может сойти с рук, если тип содержит только элементы встроенных типов и не имеет указателей, но технически это вызывает неопределенное поведение.
Вызывать неопределенное поведение плохо, потому что это позволяет вашей программе делать что угодно.Это может привести к сбою вашей программы, молчаливому получению неверных результатов, форматированию жесткого диска, сгоранию вашего процессора, забеременеть, или это может работать так, как вы ожидали.Теперь он может вести себя по-разному, но по-разному с новой версией компилятора, обновлением ОС, на другой платформе, на сайте клиента, когда ваш начальник смотрит, по воскресеньям или в зависимости от фазы луны.

Конструктор - это то, что превращает необработанную память в действительный объект.Конструкторы запускаются автоматически, когда вы создаете объекты в стеке, глобальные объекты или используете выражение new.Вы можете разделить выделение памяти и конструкцию, используя размещение новых .Сделав это, вы можете взять память, выделенную std::malloc(), и вызвать для нее конструктор.Но почему вы хотите это сделать?За исключением оптимизации (и как механизма, используемого типами в C ++ std lib), размещение новых редко когда-либо требуется.

Почему ваш вопрос был помечен C++ в любом случае?Конечно, компилятор C ++ скомпилирует его с несколькими очевидными исправлениями, но кроме C ++ - стиля, включающего заголовки C std lib, в нем нет ничего C ++, и он полон C-isms.
Вы уверены, что выхотите программировать на C ++?Или тебе не удобнее с С?Если это так, то лучше придерживаться C, чем писать C на C ++.Многое из того, что считается хорошим в C, считается плохим в C ++.

0 голосов
/ 18 сентября 2010

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

На самом деле нет,это специфика компилятора.Также рассмотрим такой фрагмент программного кода:

#include <stdio.h>

int i;

int main() {
  while (i<10) {
    printf("Hello\n");
    i++;
  }
  return 0;
}

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

То же самое вернодля вашего кода.С помощью malloc вы получаете фрагмент памяти для вашей переменной, но вы не инициализируете .Поэтому вы можете получить неожиданное поведение, используя эту переменную, поэтому вам следует инициализировать ее с помощью конструктора.

С помощью конструктора вы получаете гарантию, что по крайней мере некоторые поля объекта установлены так, как требуется, но с malloc вы знаетеничего о фактических значениях полей.

Также смотрите эту ссылку .Четко сказано, что malloc ничего не инициализирует.Кроме того, вы должны всегда явно освобождать память после вызова malloc, иначе вы получите утечки памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...