C ++ 구조체를 초기화하는 적절한 방법


82

우리 코드는 POD (Plain Old Datastructure) 구조체 (처음에 초기화해야하는 다른 구조체와 POD 변수를 포함하는 기본 C ++ 구조체입니다.)

내가 읽은 것을 기반으로 한 것 같습니다.

myStruct = (MyStruct*)calloc(1, sizeof(MyStruct));

다음과 같이 모든 값을 0으로 초기화해야합니다.

myStruct = new MyStruct();

그러나 구조체가 두 번째 방법으로 초기화 될 때 Valgrind는 이러한 변수가 사용될 때 "조건부 점프 또는 이동이 초기화되지 않은 값에 따라 달라집니다"라고 나중에 불평합니다. 내 이해에 결함이 있습니까, 아니면 Valgrind가 오탐을 던지고 있습니까?


1
또한 new MyStruct()C ++ 03에서는 패딩 바이트를 설정할 필요가 없습니다. C ++ 0x에서는 그렇습니다. 모든 패딩 비트는 C ++ 0x에서 0으로 설정됩니다.
Johannes Schaub-litb

캐치 해 주셔서 감사합니다. 제 질문을 수정했습니다.
Shadow503


내가 이해했듯이 오류 메시지가 표시되면 안됩니다. 데이터 구조가 POD가 아닐까요? 이 동작을 여전히 보여주는 가장 작은 프로그램으로 코드를 줄이고 증류 된 프로그램을 게시 할 수 있습니까? ( sscce.org 참조 ).
Robᵩ

무슨 컴파일러? MyStruct의 정의를 게시 할 수 있습니까?
Alan Stokes

답변:


120

C ++에서 클래스 / 구조체는 동일합니다 (초기화 측면에서).

POD가 아닌 구조체는 생성자를 가질 수 있으므로 멤버를 초기화 할 수 있습니다.
구조체가 POD이면 이니셜 라이저를 사용할 수 있습니다.

struct C
{
    int x; 
    int y;
};

C  c = {0}; // Zero initialize POD

또는 기본 생성자를 사용할 수 있습니다.

C  c = C();      // Zero initialize using default constructor
C  c{};          // Latest versions accept this syntax.
C* c = new C();  // Zero initialize a dynamically allocated object.

// Note the difference between the above and the initialize version of the constructor.
// Note: All above comments apply to POD structures.
C  c;            // members are random
C* c = new C;    // members are random (more officially undefined).

나는 valgrind가 C ++가 작동하는 방식이기 때문에 불평하고 있다고 생각합니다. (C ++가 0 초기화 기본 구성으로 언제 업그레이드되었는지 정확히 모르겠습니다.) 가장 좋은 방법은 객체를 초기화하는 생성자를 추가하는 것입니다 (구조체는 생성자가 허용됨).

참고로
, 많은 초보자들이 init를 중요하게 생각합니다.

C c(); // Unfortunately this is not a variable declaration.
C c{}; // This syntax was added to overcome this confusion.

// The correct way to do this is:
C c = C();

"Most Vexing Parse"에 대한 빠른 검색은 내가 할 수있는 것보다 더 나은 설명을 제공 할 것입니다.


1
C ++에서이 0 초기화 변수에 대한 참조가 있습니까? 마지막으로 들었습니다. 여전히 C. IIRC와 동일한 동작을합니다. MSVC 컴파일러는 어떤 시점에서 초기화되지 않은 멤버를 0 초기화 (성능상의 이유로) 삭제하여 다른 MS 부서에 대해 상당히 심각한 문제를 일으켰습니다. :)
Marc Mutz-mmutz

1
아니, C()하지만 당신이 옳은 것 같습니다 .
Marc Mutz-mmutz

4
포드 클래스로, T, T()제로 스칼라 하위 객체를 초기화 항상있다. 최상위 초기화의 이름은 C ++ 03에서와 C ++ 98에서 다르게 호출되었지만 ( "기본 초기화"대 "값 초기화") POD의 최종 효과는 동일합니다. C ++ 98과 C ++ 03은 모두 0이됩니다.
Johannes Schaub-litb

1
@RockyRaccoon은 C c();불행히도 변수 선언이 아니라 함수의 전방 선언입니다 (매개 변수를 취하지 않고 C 유형의 객체를 반환하는 'c'라는 함수). Google : 가장 짜증나는 구문
Martin York

1
@RockyRaccoon 여기와 귀하의 의견에 링크 된 질문의 차이점; 이 경우 생성자에서 사용되는 매개 변수가 없다는 것입니다. 따라서 컴파일러는 이것을 파싱하고 변수 선언과 함수의 포워드 선언 사이의 차이점을 알려주는 데 어려움을 겪습니다. 앞으로 함수 선언을 선택합니다. 생성자에 매개 변수가 필요한 경우 컴파일러는 이것이 문제없이 변수 선언임을 알 수 있습니다. C c(4);유효한 변수 선언입니다.
Martin York

2

당신이 우리에게 말한 바에 따르면 그것은 valgrind에서 거짓 양성으로 보입니다. new와 구문 ()은 POD 가정하고, 물체의 가치를 초기화한다.

구조체의 일부 하위 부분이 실제로 POD가 아니고 예상되는 초기화를 방해 할 수 있습니까? valgrind 오류를 표시하는 게시 가능한 예제로 코드를 단순화 할 수 있습니까?

또는 컴파일러가 실제로 POD 구조 값을 초기화하지 않을 수도 있습니다.

어쨌든 가장 간단한 해결책은 구조체 / 하위 부분에 필요한 생성자를 작성하는 것입니다.


1

테스트 코드를 작성합니다.

#include <string>
#include <iostream>
#include <stdio.h>

using namespace std;

struct sc {
    int x;
    string y;
    int* z;
};

int main(int argc, char** argv)
{
   int* r = new int[128];
   for(int i = 0; i < 128; i++ ) {
        r[i] = i+32;
   }
   cout << r[100] << endl;
   delete r;

   sc* a = new sc;
   sc* aa = new sc[2];
   sc* b = new sc();
   sc* ba = new sc[2]();

   cout << "az:" << a->z << endl;
   cout << "bz:" << b->z << endl;
   cout << "a:" << a->x << " y" << a->y << "end" << endl;
   cout << "b:" << b->x << " y" << b->y <<  "end" <<endl;
   cout << "aa:" << aa->x << " y" << aa->y <<  "end" <<endl;
   cout << "ba:" << ba->x << " y" << ba->y <<  "end" <<endl;
}

g ++ 컴파일 및 실행 :

./a.out 
132
az:0x2b0000002a
bz:0
a:854191480 yend
b:0 yend
aa:854190968 yend
ba:0 yend

좋아, 내가 너무 익숙하지 않아요 new sc;new sc();. 누락 된 괄호가 오류라고 생각했을 것입니다. 그러나 이것은 (. 기본 생성자를 사용하는 경우는 0으로 초기화하기 않음) 답이 정확하다는 것을 입증하는 것
nycynik

0

구조체에있는 모든 멤버를 초기화해야합니다. 예 :

struct MyStruct {
  private:
    int someInt_;
    float someFloat_;

  public:
    MyStruct(): someInt_(0), someFloat_(1.0) {} // Initializer list will set appropriate values

};

이 경우에는 클래스가 아니라 구조체를 사용하고 있습니다.
Shadow503

구조체는 클래스입니다. 편집 내 게시물 :
ralphtheninja

2
POD에 대해이 작업을 수행 할 필요가 없습니다
Alan Stokes

0

POD 구조체이기 때문에 항상 0으로 memset 할 수 있습니다. 이것은 필드를 초기화하는 가장 쉬운 방법 일 수 있습니다 (적절하다고 가정).


1
구조체 든 클래스 든간에 생성자를 memset하거나 생성하는 기능과는 아무 관련이 없습니다. 예를 들어, 참조 stackoverflow.com/questions/2750270/cc-struct-vs-class
에릭

생성자 (아마도)가 초기화를 수행했기 때문에 클래스를 생성 한 후에는 일반적으로 클래스를 memset하지 않습니다.
Scott C Wilson

1
기본 보호 (개인 및 공용, resp.)를 제외하고는 C ++에서 "class"와 "struct"간에 차이가 없습니다. 구조체는 비 POD 일 수 있고 클래스는 POD 일 수 있습니다. 이러한 개념은 직교합니다.
Marc Mutz-mmutz

@mmutz와 @Erik-동의-혼란을 방지하기 위해 내 대답을 단축했습니다.
Scott C Wilson

memset ()은 최선의 옵션이 아닙니다. 기본 ctor를 호출하여 POD 구조체를 0으로 초기화 할 수 있습니다.
Nils

0

그것은 나에게 가장 쉬운 방법 인 것 같습니다. 구조 멤버는 중괄호 '{}'를 사용하여 초기화 할 수 있습니다. 예를 들어 다음은 유효한 초기화입니다.

struct Point 
{ 
   int x, y; 
};  

int main() 
{ 
   // A valid initialization. member x gets value 0 and y 
   // gets value 1.  The order of declaration is followed. 
   struct Point p1 = {0, 1};  
}

C ++의 구조체에 대한 좋은 정보가있다 - https://www.geeksforgeeks.org/structures-in-cpp/

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