Чи члени структури C ++ ініціалізовані до 0 за замовчуванням?


200

У мене це struct:

struct Snapshot
{
    double x; 
    int y;
};

Я хочу xі yбути 0. Чи буде вони за замовчуванням 0 або мені це робити:

Snapshot s = {0,0};

Які ще способи зняти нульову структуру?


Використовуйте std :: map <> і повертайте 0, коли ключ не існує.
Джоні

Відповіді:


263

Вони не є нульовими, якщо ви не ініціалізуєте структуру.

Snapshot s; // receives no initialization
Snapshot s = {}; // value initializes all members

Другий зробить всі члени нульовими, перший залишить їх при невизначених значеннях. Зауважте, що це рекурсивно:

struct Parent { Snapshot s; };
Parent p; // receives no initialization
Parent p = {}; // value initializes all members

Другий зробить p.s.{x,y}нуль. Ви не можете використовувати ці сукупні списки ініціалізаторів, якщо у вашій структурі є конструктори. Якщо це так, вам доведеться додати належну ініталізацію до цих конструкторів

struct Snapshot {
    int x;
    double y;
    Snapshot():x(0),y(0) { }
    // other ctors / functions...
};

Буде ініціалізовано і x, і y 0. Зверніть увагу, що ви можете використовувати їх x(), y()для ініціалізації, не зважаючи на їх тип: Це тоді ініціалізація значень і зазвичай дає належне початкове значення (0 для int, 0,0 для подвійного, викликаючи конструктор за замовчуванням для визначеного користувачем типи, які мають оголошені користувачем конструктори, ...). Це важливо, особливо якщо ваша структура є шаблоном.


1
Це створює багато попереджень у моєму компіляторі.
Рівер-Клер Вільямсон

1
Роджер: Спробуйте використовувати названу структуру в ініціалізаторі, ось що я роблю, і я не отримую жодних попереджень у VC 2012: Snapshot s = Snapshot ();
Kit10

@Johannes Schaub - litb Буде Snapshot s = {};працювати для не членів ПОД (для їх обнулення)?
ontherocks

2
Тепер C ++ 11 дозволяє ініціалізувати їх у визначенні структури або класу, як-от так: Сніг Структури {double x {0}; // з дужками int y = 0; // або просто старий шкільний стиль "шляхом присвоєння", який теж є ініціалізацією};
ikku100

1
"Знімок s = {};" частина стандарту?
Стефан

40

Ні, за замовчуванням вони не дорівнюють 0. Найпростіший спосіб переконатись у тому, що всі значення або значення за замовчуванням до 0 - це визначення конструктора

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

Це гарантує, що для всіх застосувань Snapshot будуть ініціалізовані значення.


24
Мінус полягає в тому, що структура більше не є типом POD, оскільки вона має конструктор. Це порушить деякі операції, такі як запис у тимчасовий файл.
finnw

16
@finnw: C ++ 11 виправляє це, хоча структура не є POD, але це "стандартний макет".
Ben Voigt

19

Загалом, ні. Однак структура, оголошена як файл-область або статична у функції / буде / буде ініціалізована до 0 (як і всі інші змінні цих областей):

int x; // 0
int y = 42; // 42
struct { int a, b; } foo; // 0, 0

void foo() {
  struct { int a, b; } bar; // undefined
  static struct { int c, d; } quux; // 0, 0
}

1
Це дійсно не безпечне припущення. не варто покладатися на цінність того, що ви не ініціалізували
Hasturkun

24
Об'єкти статичної тривалості зберігання завжди ініціалізуються до нуля - див. Stackoverflow.com/questions/60653/… цитування зі стандарту. Чи хороший це стиль - інша справа.
бдонлан

12

З POD Ви також можете писати

Snapshot s = {};

Не слід використовувати memset в C ++, у memset є недолік, що якщо в структурі є не-POD, він зруйнує його.

або так:

struct init
{
  template <typename T>
  operator T * ()
  {
    return new T();
  }
};

Snapshot* s = init();

@LightnessRacesinOrbit ой ват?
Бен Сінклер

@Andy Most Vexing Parse перетворює речі, схожі на звичайні цитри, - SomeType foo();типовий, хоча це може статися і з іншими - у визначення функцій (у такому випадку функція, fooяка повертається SomeType). Вибачте за некро, але якщо хтось інший наткнеться на це, я подумав, що я відповім.
Фонд позову Моніки

7

У C ++ використовуйте конструктори без аргументів. У C ви не можете мати конструктори, тому використовуйте memsetабо - цікаве рішення - призначені ініціалізатори:

struct Snapshot s = { .x = 0.0, .y = 0.0 };

Я вважаю, що це C, а не C ++. Не вдасться компілювати під деякими компіляторами C ++. Я зазнав помилки компіляції під Cygwin або MinGW.
jww

3

Я вважаю, що правильна відповідь полягає в тому, що їх значення не визначені. Часто вони ініціалізуються на 0 при запуску налагоджених версій коду. Зазвичай це не так при запуску версій версій.


2
Власне, налагоджені версії просто є 0в тих місцях пам'яті. Це не те саме, що ініціалізація!
Гонки легкості на орбіті

3

Оскільки це ПОД (по суті є С-структурою), мало шкоди при його ініціалізації шляхом С:

Snapshot s;
memset(&s, 0, sizeof (s));

або аналогічно

Snapshot *sp = new Snapshot;
memset(sp, 0, sizeof (*sp));

Я б не пішов так далеко, щоб використовувати calloc()в програмі C ++.


3
Те саме стосується подвійних; all-bits-zero не обов'язково 0,0. Однак ви можете перевірити, чи є у вас подвійні IEEE754, і в цьому випадку він повинен працювати.
MSalters

1

Перемістіть членів стручка до базового класу, щоб скоротити список ініціалізатора:

struct foo_pod
{
    int x;
    int y;
    int z;
};

struct foo : foo_pod
{
    std::string name;
    foo(std::string name)
        : foo_pod()
        , name(name)
    {
    }
};

int main()
{
    foo f("bar");
    printf("%d %d %d %s\n", f.x, f.y, f.z, f.name.c_str());
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.