У меня есть два типа инициализации структурных переменных в моем коде.
пример
#include<iostream>
#include<string>
using namespace std;
struct Data{
int arr[5];
float x;
};
int main(){
struct Data d = {0};
struct Data d1 = {};
cout<<d.arr[0]<<d.x;
cout<<d1.arr[0]<<d1.x<<endl;
return 0;
}
Я запускаю код объявления, получая 0 0 0 0 в качестве вывода. Пожалуйста, помогите мне, есть ли разница между обеими инициализацией.
Согласно правилу агрегатная инициализация, эффект здесь одинаков, то есть все члены структуры будут Значение инициализирован (нулевой инициализируется здесь для неклассных типов).
Если количество пунктов инициализатора меньше, чем количество членов
and bases (since C++17)
или список инициализаторов полностью пуст, остальные членыand bases (since C++17)
инициализируютсяby their default initializers, if provided in the class definition, and otherwise (since C++14)
пустыми списками в соответствии с обычными правилами инициализации списков (которые выполняют инициализацию значений для типов, не относящихся к классам и неагрегированных классов с конструкторами по умолчанию, и инициализацию агрегатов для агрегатов). Если член ссылочного типа является одним из этих оставшихся членов, программа является некорректной.
Точнее,
struct Data d = {0}; // initialize the 1st member of Data to 0, value-initialize(zero-initialize) the remaining members
struct Data d1 = {}; // value-initialize(zero-initialize) all the members of Data
Обратите внимание, что вся история основана на том, что Data
является тип агрегата и его члены не являются типами классов, иначе поведение изменилось бы в соответствии с правилом инициализация списка.
Результат такой же в этом случае, но не обязательно так в других случаях.
В этом случае вы не предоставили ctor, поэтому вы используете агрегатную инициализацию. Это дает нулевую инициализацию для пустого списка инициализации, а вы предоставляете 0 для непустого, так что оба работают одинаково.
Если бы вы предоставили ctor, было бы тривиально получить разные результаты из двух:
#include <iostream>
struct foo {
int f;
foo(int f = 5) : f(f) {}
friend std::ostream &operator<<(std::ostream &os, foo const &f) {
return os << f.f;
}
};
int main() {
foo f1{};
foo f2{0};
std::cout << "Empty init list: " << f1 << "\n";
std::cout << "zero init list: " << f2 << "\n";
}
Хотя ctor — самый очевидный способ сделать это, это не единственный. Для другого очевидного примера (только C ++ 11 и новее):
struct foo {
int f = 5;
};
инициализация по умолчанию использование {} определяется как инициализация каждый участник используя {}. Итак, делая
struct Data d1 = {};
Data d1
инициализируется в {{},{}}
, который {{0, 0, 0, 0, 0}, 0.0}
,
как 0
а также 0.0
значения по умолчанию для int
а также float
соответственно
По этой причине вы не видите никакой разницы. Они оба неизменно делают одно и то же в вашем случае.
Различия заключаются в следующих случаях:
1.) Это при предоставлении инициализатора внутри {}
становится обязательный:
struct X {
X(int);
};
X x1 {}; // error : empty initializer. X(int) states that an int is required to construct an X.
X x2 {0}; // OK
2.) Сценарий, когда нулевая инициализация запрещено:
struct Test {
string name;
int year;
};
Test alpha0{0}; // Error. Because name in Test fails at zero-initialization.
Test alpha{}; // OK. Because name in Test is default-initialized with empty string "".
Да, есть разница. В первом случае вы явно инициализируете первый член Data
(arr[0]
) к нулю. Во втором случае вы ничего не инициализируете и просто читаете, какое значение там окажется. В этом случае он также был равен нулю, но это не гарантировано, особенно в более сложной программе.
Всегда хорошая идея инициализировать всех членов структуры. Рассмотрим эту слегка измененную версию вашей программы, которая должна прояснить происходящее:
#include<iostream>
#include<string>
using namespace std;
struct Data{
int arr[5];
float x;
};
int main(){
struct Data d = {1, 2, 3, 4, 5, 3.14f};
struct Data d1 = {};
cout<<d.arr[0]<<", "<<d.x<<", ";
cout<<d1.arr[0]<<", "<<d1.x<<endl;
return 0;
}
Это напечатает:
1, 3.14, 0, 0