1

Тема: Чому дані класу не зануляються?

Вітаю,

ніяк не можу зрозуміти, чому замість нулів виводить якийсь мусор (Point pt1) -858993460, -858993460 ?
Я вже пробував різні варіанти, навіть без конструктора, але навіть в такому випадку виводить -858993460 замість 0, в чому помилка? Конструктор по замовчуванню мав би обнулити.

#include <iostream>
using namespace std;
 
class Point {
private:
       int x, y;
public:
       Point() {}
       int get_x() {return x;}
       int get_y() {return y;}
};
 
int main() {
    Point pt1;
    cout << pt1.get_x() << ", ";
    cout << pt1.get_y() << endl; 
    return 0;
}

2

Re: Чому дані класу не зануляються?

Це якраз звичайна поведінка. Ви десь маєте вказати, що хочете саме нулі, або робити статичні змінні - в локальних та динамічних буде сміття.

6.7.4 Indeterminate values [basic.indet]
1 When storage for an object with automatic or dynamic storage duration is obtained, the object has an
indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate
value until that value is replaced (7.6.19). [Note: Objects with static or thread storage duration are
zero-initialized, see 6.9.3.2. — end note]

Раджу вказувати явно, як зараз прийнято:

int x {};
int y {};

Можна, звісно, і в конструкторі

Point():x(0),y(0){}

Статика:

static Point pt1; //нулі

Глобальна змінна:

Point pt1;//нулі
int main() {

Навіть так:

Point pt1 = Point();//якщо це ваш конструктор без ініціалізації, то буде сміття, але якщо ви його видалите - будуть нулі
Подякували: mimik, ostap34PHP2

3

Re: Чому дані класу не зануляються?

З цим зрозуміло. Проясніть тоді, будь ласка, такий момент, якщо я правильно розумію, то конструктор за замовчуванням, який додається компілятором, встановлює всі дані-члени в нуль, а всім вказівниками присвоюються нульові значення?

4

Re: Чому дані класу не зануляються?

Будете сміятися, але... ні.
https://repl.it/@pavloslav/zeroing

код
#include <iostream>
using namespace std;
 
class WithDefaultCtr {
private:
       int value;
public:
       WithDefaultCtr() {}
       int get() {return value;}
};

class NoDefaultCtr {
private:
       int value;
public:
       int get() {return value;}
};

WithDefaultCtr global_with;
NoDefaultCtr global_no;

int main() {
    WithDefaultCtr local_with;
    NoDefaultCtr local_no;
    WithDefaultCtr local_with_inited = WithDefaultCtr();
    NoDefaultCtr local_no_inited = NoDefaultCtr();
    cout << "Global with: " << global_with.get()
         << "\nGlobal no: " << global_no.get()
         << "\nLocal with: " << local_with.get()
         << "\nLocal no: " << local_no.get()
         << "\nLocal With Inited: " << local_with_inited.get()
         << "\nLocal No Inited: " << local_no_inited.get()
         << endl;

    return 0;
}

Результат:

Global with: 0
Global no: 0
Local with: 0
Local no: -257180144
Local With Inited: 4196272
Local No Inited: 0

Якщо вам треба, щоб гарантовано були нулі - ініціалізуйте руками, інакше десь можуть бути не нулі.

Подякували: leofun011

5

Re: Чому дані класу не зануляються?

mimik написав:

З цим зрозуміло. Проясніть тоді, будь ласка, такий момент, якщо я правильно розумію, то конструктор за замовчуванням, який додається компілятором, встановлює всі дані-члени в нуль, а всім вказівниками присвоюються нульові значення?

Ні, compiler-provided constructor нічим таким не зобов'язаний займатися. З чого ви це взяли?
По суті це теж, що і пустий конструктор, такий же як у вашому прикладі. Загалом, якщо я не помиляюся стандарт нічого про це не каже, а отже в теорії компілятор може сам проініціалізувати, але я б не став на це опиратися, краще самому прописати.

Це ж і відноситься до вашого пустого конструктору, з чого б це він мав сам здогадатись, що йому тре ініціалізувати нулем?

Подякували: mimik, leofun012

6

Re: Чому дані класу не зануляються?

koala, так, ось так працює:

Point pt1 = Point();

Але чому?
wander, про те, що мало би занулювати писало в книжці.

Подякували: wander1

7 Востаннє редагувалося wander (12.02.2020 17:13:24)

Re: Чому дані класу не зануляються?

mimik написав:

Але чому?

Бо це вже трохи інша пара калошів.
Це вже відноситься до ініціалізації, ніж до конструкторів як таких.

https://eel.is/c++draft/dcl.init#11 написав:

An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.
[ Note: Since () is not permitted by the syntax for initializer,

X a();

is not the declaration of an object of class X, but the declaration of a function taking no argument and returning an X.
The form () is permitted in certain other initialization contexts. — end note ]

А вже value-initialization, якщо ви не визначили власний конструктор по замовчуванню, зробить для вас zero-initialization.

https://eel.is/c++draft/dcl.init#8.2 написав:

— if T is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then the object is zero-
initialized
and the semantic constraints for default-initialization are checked, and if T has a non-trivial default constructor, the object is default-initialized;

mimik написав:

про те, що мало би занулювати писало в книжці.

Це в якій такій?

Подякували: mimik, leofun012

8 Востаннє редагувалося koala (12.02.2020 17:53:22)

Re: Чому дані класу не зануляються?

Ну, десь так.
В C++ є дуже багато способів щось записати. ДУЖЕ.

Point pt;
Point pt();
Point pt{};
Point pt=Point();
Point pt=Point{};
Point pt={Point{}};//а чому б ні?

і це можна помножити на усталені конструктори і конструктори копіювання - автоматичні чи визначені - у відповідних місцях.
У 90% випадків все це буде або приводитися до приблизно одного того й самого оптимізатором, або матиме незначну різницю в швидкодії та витратах пам'яті.
Особисто я раджу:
- явно прописувати всі значення;
- явно визначати (чи видаляти) всі конструктори при найменших сумнівах у їхній правильності (явне краще за неявне);
- і лише якщо код жере забагато ресурсів, починати лізти в деталі, скасовувати ініціалізації, проставляти правильні конструктори і т.д.

C++ не буде за вас нічого ініціалізувати. Ну, насправді іноді буде, але не розраховуйте на це, доки не буде критичної потреби в оптимізації. Ясно?

Подякували: mimik, leofun012

9

Re: Чому дані класу не зануляються?

Може, так буде краще зрозуміти: всі ці складні правила ініціалізації в C++ придумані не для того, щоб ви могли зекономити 10 натискань на клавіші при написанні коду, а для того, щоб ви могли абсолютно точно сказати компілятору, що йому треба робити, а чого не треба, і зекономити в результаті пару тактів при виконанні коду. Не економте на натисканнях.

Подякували: mimik, leofun012

10

Re: Чому дані класу не зануляються?

А вже value-initialization, якщо ви не визначили власний конструктор по замовчуванню, зробить для вас zero-initialization.

Зрозуміло.

Це в якій такій?

Прихований текст

https://i.gyazo.com/611fb2d99278d386e1e77e9f1ac844d2.png
С++ без страха, Брайан Оверленд

Ясно?

Більш менш

11

Re: Чому дані класу не зануляються?

mimik, кидайте ту книгу, автор здається мухоморів об'ївся.

Подякували: mimik1

12

Re: Чому дані класу не зануляються?

І от ще:

Прихований текст

https://i.gyazo.com/e387190364edea9e645210b2281a0fb8.png

mimik, кидайте ту книгу, автор здається мухоморів об'ївся.

А, що можете порадити?

Подякували: wander1

13 Востаннє редагувалося wander (12.02.2020 19:25:20)

Re: Чому дані класу не зануляються?

mimik написав:

І от ще:

Багато мухоморів об'ївся, може не тільки їх :D

mimik написав:

А, що можете порадити?

Ліпмана (більш доступна) або Страуструпа (складніша, від розробника С++).

  1. C++ Primer, 5th Edition by Stanley B. Lippman, Josée Lajoie, Barbara E. Moo

  2. The C++ Programming Language, 4th Edition by Bjarne Stroustrup

До речі в С++03, default-initialization виглядала по іншому, ніж зараз:

C++03 8.5/5 написав:

To default-initialize an object of type T means:

  • if T is a non-POD class type, the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);

  • if T is an array type, each element is default-initialized;

  • otherwise, the object is zero-initialized.

Тобто, якщо ваш клас POD і ви не передбачили для нього ініціалізатор, застосуються правила ініціалізації за замовчуванням (компілятор згенерує default-constructor), де згідно з правилом вище відбудеться zero-initialization. Але все одно те, що пише автор в тій книжці, як мінімум потребує детальнішого пояснення.

Подякували: mimik1

14

Re: Чому дані класу не зануляються?

wander, дякую за літературу, напевно зупинюся на першому варіанті.
То, автор в книжці правий чи ні?
І що таке POD?

Подякували: wander1

15

Re: Чому дані класу не зануляються?

POD - plain old data, структура без ООП-шних примочок.
Я б радив менше довіряти книжкам, трохи більше - стандарту, а найбільше - авторам компіляторів.

Подякували: mimik1

16 Востаннє редагувалося wander (12.02.2020 19:43:55)

Re: Чому дані класу не зануляються?

mimik написав:

То, автор в книжці правий чи ні?

Ні, не правий.

mimik написав:

І що таке POD?

POD — розшифровується Plain Old Data.
Приблизно цей "тип" можна представити так:

POD = { (public | private | protected) + (fundamental | POD)* }

Чому приблизно? Бо комітет зі стандартизації любить кожного разу змінювати визначення, з С++20 PODи взагалі прибрали замінивши на trivial, але це менш важливо.
Отже Plain Old Data — це структура, всі поля якої або public, або private, або protected і всі поля-члени цієї структури або фундаментальні типи (вказівники, char, int, nullptr_t, etc), або інші POD. І більше нічого, ніяких конструкторів, деструкторів, операторів копіювання, віртуальних функцій і тд.

Подякували: mimik, koala2

17

Re: Чому дані класу не зануляються?

Зрозуміло, дякую.

Подякували: wander1