Bir C ++ yapısının üyeleri varsayılan olarak 0'a mı ayarlandı?


201

Bende bu var struct:

struct Snapshot
{
    double x; 
    int y;
};

Ben istiyorum xve y0 olmak. Varsayılan olarak 0 olacak mı ya da yapmak zorunda:

Snapshot s = {0,0};

Yapıyı sıfırlamanın diğer yolları nelerdir?


Bir std :: map <> kullanın ve bir anahtar olmadığında 0 değerini döndürün.
Jonny

Yanıtlar:


264

Yapıyı başlatmazsanız bunlar boş olmaz.

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

İkincisi tüm üyeleri sıfırlar, birincisi onları belirtilmemiş değerlerde bırakır. Yinelemeli olduğuna dikkat edin:

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

İkincisi p.s.{x,y}sıfır yapar. Yapınızda yapı oluşturucular varsa bu toplu başlatıcı listelerini kullanamazsınız. Eğer durum buysa, bu inşaatçılara uygun initalizasyon eklemeniz gerekecek

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

Hem x hem de y'yi 0'a x(), y()başlatacaktır. Türlerini dikkate almadan başlatmak için kullanabileceğinizi unutmayın : Bu daha sonra değer başlatmadır ve genellikle uygun bir başlangıç ​​değeri verir (int için 0, double için 0.0, kullanıcı için varsayılan yapıcı çağrılır kullanıcının yapıcı olarak bildirdiği türler, ...) Bu, özellikle yapınız bir şablonsa önemlidir.


1
Bu, derleyicimde çok sayıda uyarı üretir.
River-Claire Williamson

1
Roger: Başlatıcıda adlandırılmış yapı kullanmaya çalışın, yaptığım bu ve VC 2012'de herhangi bir uyarı almıyorum: Snapshot s = Snapshot ();
Kit10

@Johannes Schaub - litb Snapshot s = {};POD üyesi olmayanlar için çalışacak (onları sıfırlamak için)?
ontherocks

2
C ++ 11 şimdi bunları yapı veya sınıf tanımında başlatmanıza izin verir, şöyle: struct Snapshot {double x {0}; // parantez ile int y = 0; // ya da gerçekten de ilklendirme olan 'atama ile' eski okul tarzı};
ikku100

1
"Anlık görüntü s = {};" standardın bir parçası?
Stefan

41

Hayır, varsayılan olarak 0 değildir. Tüm değerlerin veya varsayılan 0 olarak ayarlandığından emin olmanın en basit yolu bir yapıcı tanımlamaktır

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

Bu, tüm Anlık Görüntü kullanımlarının başlangıç ​​değerlerine sahip olmasını sağlar.


24
Dezavantajı, yapının artık bir POD tipi olmamasıdır, çünkü bir yapıcıya sahiptir. Bu, geçici bir dosyaya yazmak gibi bazı işlemleri bozacaktır.
finnw

16
@finnw: C ++ 11 bunu düzeltir, ancak yapı POD olmasa da "standart düzen" dir.
Ben Voigt

20

Genel olarak, hayır. Bununla birlikte, bir işlevde dosya kapsamı veya statik olarak bildirilen bir yapı / 0 olarak başlatılır / sıfırlanır (bu kapsamların diğer tüm değişkenleri gibi):

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
Bu gerçekten güvenli bir varsayım değil. başlatmadığınız hiçbir şeyin değerine güvenmemelisiniz
Hasturkun

24
Statik depolama süresi nesneleri her zaman sıfıra sıfırlanır - standarttan alıntı yapmak için stackoverflow.com/questions/60653/… adresine bakın . Bunun iyi bir stil olup olmadığı başka bir konudur.
bdonlan

12

POD ile ayrıca yazabilirsiniz

Snapshot s = {};

Memset'i C ++ ile kullanmamalısınız, memset, yapıda POD olmayan bir varsa onu yok edecek dezavantajına sahiptir.

ya da bunun gibi:

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

Snapshot* s = init();

@LightnessRacesinOrbit oh wat?
Ben Sinclair

@Ve Çoğu Vexing Ayrıştırma, normal ktorlara benzeyen şeyleri - SomeType foo();diğerleriyle birlikte olsa da tipik olanı - işlev tanımlarına (bu durumda foogeri dönen bir işlev SomeType) dönüştürür. Necro için özür dilerim, ama eğer başka biri tökezlese, cevap vereceğimi düşündüm.
Monica'nın Davası

8

C ++ 'da, bağımsız değişken yapıcıları kullanın. C'de yapıcılarınız olamaz, bu yüzden ya memsetda - ilginç çözüm - belirlenmiş başlatıcıları kullanın:

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

Bunun C ++ değil C olduğuna inanıyorum. Bazı C ++ derleyicileri altında derlenemez. Derleme hatasını Cygwin veya MinGW altında yaşadım.
jww

3

Doğru cevabın değerlerinin tanımsız olduğuna inanıyorum. Genellikle, kodun hata ayıklama sürümlerini çalıştırırken 0 olarak başlatılırlar. Yayın sürümlerini çalıştırırken genellikle durum böyle değildir.


2
Aslında hata ayıklama sürümleri zaten 0bellekte bu yerlerde var olur . Bu, başlatma ile aynı şey değildir!
Yörüngedeki Hafiflik Yarışları

3

Bu bir POD (esas olarak bir C yapısı) olduğundan, C yolunun başlatılmasında çok az zarar vardır:

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

veya benzer şekilde

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

Şimdiye kadar calloc()bir C ++ programında kullanmak için gitmek değildir .


3
Aynı şey çift için de geçerlidir; all-bit-zero mutlaka 0.0 değildir. Ancak, IEEE754'ün çift olup olmadığını kontrol edebilirsiniz, bu durumda çalışması gerekir.
MSalters

1

Başlatıcı listenizi kısaltmak için bölme üyelerini temel sınıfa taşıyın:

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());
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.