Что приведет к тому, что члены данных в классе будут инициализированы нулями? - PullRequest
1 голос
/ 30 октября 2019

Конструктор по умолчанию не должен обнулять какой-либо элемент данных. Но в некоторых ситуациях это выглядит не так.

Пример кода краткий.

#include <iostream>

using namespace std;

class Foo {
public:
  int val;
  Foo() = default;
};

int main() {
  Foo bar;
  if (bar.val != 0) {
    cout << "true" << endl;
  } else {
    cout << "false" << endl;
  }
  return 0;
}

Как указано выше, вышеприведенные выходные данные программы:

true

Однако, если добавлен оператор печати для элемента данных бара, элемент var будет инициализирован нулем:

...
int main() {
  Foo bar;
  cout << bar.val << endl;
  ...
}

Выходные данные будут:

0
false

Аналогично, если добавитьвиртуальная функция и деструктор для класса Foo:

#include <iostream>

using namespace std;

class Foo {
public:
  virtual void Print() {}
  ~Foo() {}
  int val;
  Foo() = default;
};

int main() {
  Foo bar;
  if (bar.val != 0) {
    cout << "true" << endl;
  } else {
    cout << "false" << endl;
  }
  return 0;
}

или просто объект init bar:

class Foo {
public:
  int val;
  Foo() = default;
};

int main() {
  Foo bar = Foo();
  ...
}

выводит с:

false

Так что жепричина, которая влияет на значение члена класса? Разве все эти тесты не должны выводиться с true?

Ответы [ 2 ]

5 голосов
/ 30 октября 2019

При инициализации по умолчанию в этом случае:

в противном случае ничего не делается: объекты с автоматической продолжительностью хранения (и их подобъекты) инициализируются неопределенными значениями.

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

0 голосов
/ 30 октября 2019

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

неопределенное значение включает 0 неверно для main, оно вызывается один раз и первым, поэтому локальные данные определены и равны нулю. Конечно, с точки зрения языкового стандарта значение является неопределенным в общем, но определяется с точки зрения реализации ОС (зависит от реализации).

Могут быть исключения, когда сборки sanitizer могут инициализировать стексо специальными значениями защиты.

...