연산자 new는 메모리를 0으로 초기화합니다.


79

다음과 같은 코드가 있습니다.

#include <iostream>

int main(){
  unsigned int* wsk2 = new unsigned int(5);
  std::cout << "wsk2: " << wsk2 << " " << *wsk2 << std::endl;
  delete wsk2;
  wsk2 = new unsigned int;
  std::cout << "wsk2: " << wsk2 << " " << *wsk2 << std::endl;
  return 0;
}

결과:

wsk2: 0x928e008 5
wsk2: 0x928e008 0

new0으로 메모리를 초기화하지 않는 것을 읽었습니다 . 그러나 여기에있는 것 같습니다. 어떻게 작동합니까?


2
그렇지 않습니다. 새로운 unsigned int ()를 사용해야합니다. 초기화되지 않은 변수를 읽는 것은 UB이며 0은 확실히 가능합니다.
Hans Passant 2011 년

1
제쳐두고, 실제로 많은 메모리는 어쨌든 0입니다. 큰 메모리 청크의 일반 malloc을 수행하면 종종 일부 시스템에서는 모두 0이거나 다른 시스템에서는 대부분 0입니다.
Nicholas Wilson

2
@NicholasWilson : 대부분의 시스템에서 이는 메모리가 OS에서 직접 가져온 경우에만 해당됩니다 (보안상의 이유로). 할당 자에 의해 캐시 된 메모리에서 왔을 때 free () d 이전에 수행 한 작업이 포함되었을 가능성이 큽니다. 이것은 또한 그러한 버그가 때때로 테스트 케이스 / 단위 테스트에서 발생하지 않고 "실제"프로그램이 실행 된 후에 만 ​​발생하는 이유이기도합니다. Valgrind가 여기서 구출합니다.
PlasmaHH 2011 년

예. 그게 내 요점입니다. 새 변수를 만들고 그것이 0이라는 것을 알면 프로그램 내의 무언가가 그것을 0으로 설정했다고 곧바로 가정 할 수 없습니다. 대부분의 메모리는 준비된 상태로 제공되기 때문에 아직 초기화되지 않은 것 같습니다. 질문자는 왜 초기화되지 않은 기억이 0이 될 수 있는지 알고 싶어했기 때문에 아래의 대부분의 답변보다 실제로 질문에 대한 답변에 더 가깝다고 생각합니다.
Nicholas Wilson

배열을 할당하고 모든 항목을 0이 아닌 값으로 설정 한 다음 삭제 []하고 다시 할당합니다. 첫 번째 항목 만 0으로 설정되고 다른 항목은 값을 유지합니다. 이것은 메모리 할당 자 (Linux에서 테스트 됨)의 비정상 성이라고 생각합니다. ).
kyku

답변:


203

두 가지 버전이 있습니다.

wsk = new unsigned int;      // default initialized (ie nothing happens)
wsk = new unsigned int();    // zero    initialized (ie set to 0)

배열에서도 작동합니다.

wsa = new unsigned int[5];   // default initialized (ie nothing happens)
wsa = new unsigned int[5](); // zero    initialized (ie all elements set to 0)

아래 의견에 대한 답변.

음 ... new unsigned int[5]()정수 를 0으로 만드는 것이 확실 합니까?

분명히 그렇습니다 :

[C ++ 11 : 5.3.4 / 15] : T 유형의 개체를 생성하는 new-expression은 다음과 같이 해당 개체를 초기화합니다. new-initializer가 생략되면 개체는 default-initialized (8.5)입니다. 초기화가 수행되지 않으면 개체의 값이 결정되지 않습니다. 그렇지 않으면 새 초기화 프로그램은 직접 초기화를위한 8.5의 초기화 규칙에 따라 해석됩니다.

#include <new>
#include <iostream>


int main()
{
    unsigned int   wsa[5] = {1,2,3,4,5};

    // Use placement new (to use a know piece of memory).
    // In the way described above.
    // 
    unsigned int*    wsp = new (wsa) unsigned int[5]();

    std::cout << wsa[0] << "\n";   // If these are zero then it worked as described.
    std::cout << wsa[1] << "\n";   // If they contain the numbers 1 - 5 then it failed.
    std::cout << wsa[2] << "\n";
    std::cout << wsa[3] << "\n";
    std::cout << wsa[4] << "\n";
}

결과 :

> g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.2.0
Thread model: posix
> g++ t.cpp
> ./a.out
0
0
0
0
0
>

그리고 오버로드 된 new/new[]연산자는 어떻습니까? 윌 new unsigned int[5]()여전히 독점, 전혀 관계가없는 구현이 경우에도 배열을 제로는 초기화?
SomeWittyUsername

2
@icepack : operator new사용자 (개발자) 정의 함수로 원하는대로 할 수 있습니다. 표준은이 함수가하는 일에 제약을 두지 않습니다. 마찬가지로 operator==사용자가 정의한 모든 작업을 수행 할 수 있습니다 (동등성 테스트는 말할 것도없고 bool을 반환 할 필요조차 없습니다 (그렇지 않으면 잘못된 형식이지만)).
마틴 뉴욕

1
감사. 명확하게 말하면, 내 독점 할당 자의 구현은 0 초기화와 관련이 없으며 ()구문 을 사용하는 경우 할당 된 개체의 유형 및 생성자와 관계없이 버퍼가 0으로 초기화됩니다. (그리고 나는이 측면에서 아무 것도 변경하지 않는 C ++ 11 가정)
SomeWittyUsername

1
음 ... 정수 를 0으로 만드는 것이 확실new unsigned int[5]() 합니까?
궤도에서 가벼운 경주

1
@ J3STER 새 호출로 포인터를 전달하는 것을 새 배치라고합니다. 을 참조하십시오 8.3.4 New. 수정 된 이유. 가치 초기화를 강요하고 있기 때문입니다. 을 참조하십시오 11.6 Initializers. new 연산자에 대한 포인터를 전달하고 있습니다. 의 값은 wsa변경되지 않으며 변경된 것을 가리키는 주소입니다.
Martin York

21

operator new메모리를 초기화하는 것이 보장되지 않으며 new-initializer 없이 를 할당하는 new-expression 은 개체를 불확실한 값으로 남겨 둡니다.unsigned int

초기화되지 않은 개체의 값을 읽으면 정의되지 않은 동작이 발생 합니다. 정의되지 않은 동작 에는 악영향없이 값 0으로 평가하는 것이 포함되지만 결과가 발생할 수 있으므로 발생하지 않도록해야합니다.

C ++ 11에서 사용되는 언어는 할당 된 객체가 기본적으로 초기화 된다는 것입니다. 이는 클래스가 아닌 유형의 경우 초기화가 수행되지 않음을 의미합니다. 이것은 C ++ 03에서 default-initialized 의 의미와 다릅니다 .


4

일부 컴파일러에서는 new의 디버그 버전이 데이터를 초기화하지만 신뢰할 수있는 것은 없습니다.

메모리가 이전 사용에서 방금 0을 가졌을 수도 있습니다. 삭제와 새로 만들기 사이에 메모리에 아무 일도 일어나지 않았다고 가정하지 마십시오. 당신이 눈치 채지 못했던 배경에서 뭔가를 할 수 있습니다. 또한 동일한 포인터 값이 동일한 실제 메모리가 아닐 수도 있습니다. 메모리 페이지가 이동되고 페이지 아웃 및 인됩니다. 포인터는 이전과 완전히 다른 위치에 매핑 될 수 있습니다.

결론 : 메모리 위치를 특별히 초기화하지 않았다면 그 내용에 대해 아무것도 가정 할 수 없습니다. 메모리 관리자는 메모리를 사용할 때까지 특정 실제 메모리 위치를 할당하지 않을 수도 있습니다.

현대의 메모리 관리는 놀랍도록 복잡하지만 C ++ 프로그래머는별로 신경 쓰지 않습니다 (대부분 ‡). 규칙에 따라 플레이하면 문제가 발생하지 않습니다.

‡ 페이지 폴트를 줄이기 위해 최적화하는 것이 좋습니다.


3

그건 아니에요 operator new의 그, new연산자. 실제로 큰 차이가 있습니다! 차이점은 operator new원시 메모리를 반환하는 함수입니다. new연산자 를 사용할 때 생성자를 호출합니다. 그 값을 설정하는 것은 생성자가 int아니라 operator new.


5
올바른 용어는 해당하는 새 연산자를 호출하는 "새 표현식"이라고 생각합니다.
Kerrek SB 2011
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.