C ++ 구조체의 멤버는 기본적으로 0으로 초기화됩니까?


200

나는 이것을 가지고있다 struct:

struct Snapshot
{
    double x; 
    int y;
};

나는 0이 x되고 싶다. y기본적으로 0이되어야합니까, 아니면해야합니까 :

Snapshot s = {0,0};

구조를 제로화하는 다른 방법은 무엇입니까?


std :: map <>을 사용하고 키가 없으면 0을 리턴하십시오.
Jonny

답변:


263

구조체를 초기화하지 않으면 null이 아닙니다.

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

두 번째는 모든 멤버를 0으로 만들고 첫 번째는 지정되지 않은 값으로 남겨 둡니다. 재귀 적입니다.

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

두 번째는 p.s.{x,y}0이됩니다. 구조체에 생성자가 있으면 이러한 집계 초기화 목록을 사용할 수 없습니다. 이 경우 해당 생성자에 적절한 초기화를 추가해야합니다.

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

x와 y를 모두 0 x(), y()으로 초기화합니다. 유형에 관계없이 초기화하는 데 사용할 수 있습니다 . 그런 다음 값을 초기화하고 일반적으로 적절한 초기 값 (int의 경우 0, double의 경우 0.0, 사용자 정의의 기본 생성자를 호출) 사용자가 생성자를 선언 한 유형, ...). 구조체가 템플릿 인 경우 특히 중요합니다.


1
컴파일러에서 많은 경고가 발생합니다.
River-Claire Williamson

1
Roger : 이니셜 라이저에서 명명 된 구조체를 사용해보십시오. 이것이 제가하는 일이며 VC 2012에서는 경고가 표시되지 않습니다. Snapshot s = Snapshot ();
Kit10

@Johannes Schaub-litb Snapshot s = {};POD 회원이 아닌 사람 (제로화)에게 적용됩니까?
ontherocks

2
C ++ 11에서는 다음과 같이 구조체 또는 클래스의 정의에서 초기화 할 수 있습니다. struct Snapshot {double x {0}; // 중괄호 int y = 0; // 또는 실제로 초기화되는 구식 스타일 '지정에 의한 것'};
ikku100

1
"스냅 샷 s = {};" 표준의 일부?
Stefan

40

아니요, 기본적으로 0이 아닙니다. 모든 값을 유지하거나 기본값을 0으로 설정하는 가장 간단한 방법은 생성자를 정의하는 것입니다

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

이렇게하면 모든 Snapshot 사용시 초기화 된 값이 유지됩니다.


24
단점은 구조체가 생성자를 가지고 있기 때문에 더 이상 POD 유형이 아니라는 것입니다. 임시 파일에 쓰는 것과 같은 일부 작업이 중단됩니다.
finnw

16
@finnw : C ++ 11에서이 문제를 해결하지만 구조체는 POD가 아니지만 "표준 레이아웃"입니다.
벤 Voigt

19

일반적으로 아닙니다. 그러나 / scope / 함수에서 file-scope 또는 static으로 선언 된 구조체는 해당 범위의 다른 모든 변수와 마찬가지로 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
정적 저장 기간 객체는 항상 0으로 초기화됩니다 . 표준 인용에 대해서는 stackoverflow.com/questions/60653/… 을 참조하십시오 . 이것이 좋은 스타일인지 아닌지는 또 다른 문제입니다.
bdonlan

12

POD를 사용하면 다음을 작성할 수도 있습니다.

Snapshot s = {};

C ++에서는 memset을 사용하면 안됩니다. memset에는 구조체에 비 POD가 있으면이를 파괴한다는 단점이 있습니다.

또는 이와 같이 :

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

Snapshot* s = init();

@lightnessRacesinOrbit 어머?
Ben Sinclair

@Andy Most Vexing Parse는 일반적인 ctors처럼 보이는 것들을 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

이것은 POD (본질적으로 C 구조체)이므로 C 방식으로 초기화하면 거의 해가 없습니다.

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());
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.