C ++에서 새 연산자로 메모리를 초기화하는 방법은 무엇입니까?


176

방금 C ++에 들어가기 시작했고 좋은 습관을 고르고 싶습니다. 연산자를 int사용하여 유형의 배열을 방금 할당 한 경우 new직접 루프하지 않고 어떻게 0으로 초기화 할 수 있습니까? 그냥 사용해야 memset합니까? “C ++”방법이 있습니까?


19
좋은 C ++ 습관을 얻으려면 배열을 직접 사용하지 말고 대신 vector를 사용하십시오. Vector는 유형에 관계없이 모든 항목을 초기화하므로 delete [] 연산자를 호출 할 필요가 없습니다.
brianegge

@ brianegge : 배열을 외부 C 함수에 전달 해야하는 경우 벡터를 줄 수 있습니까?
dreamlax

12
통과 할 수 있습니다 &vector[0].
jamesdlin

물론 배열을 C 함수에 전달할 때는 일반적으로 @jamesdlin이 말한 것처럼 & vector [0]과 첫 번째 요소에 대한 포인터와이 경우 vector.size ()에 의해 제공되는 배열의 크기를 지정해야합니다.
Trebor Rude

관련 (배열이 아닌 유형의 경우) : stackoverflow.com/questions/7546620/…
Aconcagua

답변:


392

놀랍게도 C ++의 거의 알려지지 않은 기능이지만 (아직 아무도 이것을 대답으로 제공하지 않았다는 사실에 의해 입증 됨) 실제로 배열의 값을 초기화하는 특수 구문이 있습니다.

new int[10]();

이 점에 유의 해야한다 당신이 할 수없는, 예를 들어, 사용 - 빈 괄호를 사용 (0)하거나 다른 것 (인이 값 초기화에만 유용 이유).

이것은 ISO C ++ 03 5.3.4 [expr.new] / 15에서 명시 적으로 허용됩니다.

유형의 객체를 생성하는 새로운 표현식 T은 다음과 같이 해당 객체를 초기화합니다.

...

  • 새 이니셜 라이저가 양식 ()인 경우 항목은 값으로 초기화됩니다 (8.5).

이 유형은 허용되는 유형을 제한하지 않지만 (expression-list)양식은 배열 유형을 허용하지 않도록 동일한 섹션의 추가 규칙에 의해 명시 적으로 제한됩니다.


1
나는 이것이 거의 알려지지 않았다는 것에 동의하지만, 그것이 정말로 놀랍다는 것에 동의하지는 않습니다 .C ++ 03에 추가되었습니다. 그것은 추가했다).
Jerry Coffin

2
@ 제리 : 아직 알지 못했음을 인정해야합니다 (아마도 표준을 읽을 때 이미 C ++ 03 이었기 때문에). 즉, 내가 아는 모든 구현이 이것을 지원한다는 것은 놀랍습니다 (구현하기가 너무 간단하기 때문입니다).
Pavel Minaev

2
그렇습니다. 구현하기가 쉽지 않습니다. 지금까지 새로운 인만큼, 모든 "값 초기화"03. C ++의 새로운이었다
제리 관

34
C ++ 11에서는 균일 한 초기화도 사용할 수 있습니다 new int[10] {}. 다음과 같이 초기화 할 값을 제공 할 수도 있습니다.new int[10] {1,2,3}
bames53

default-initialized와 value-initialized를 혼동하지 마십시오. 둘 다 표준에서 명확하게 정의되어 있으며 다른 초기화입니다.
중복 제거기

25

실제로 std :: vector가 아닌 배열을 원한다고 가정하면 "C ++ 방식"은 다음과 같습니다.

#include <algorithm> 

int* array = new int[n]; // Assuming "n" is a pre-existing variable

std::fill_n(array, n, 0); 

그러나 후드 아래에서 이것은 실제로 각 요소를 0에 할당하는 루프 일뿐입니다 (하드웨어 수준 지원을 가진 특수 아키텍처를 제외하고는 실제로 다른 방법은 없습니다).


루프가 함수 아래에서 구현되는지는 신경 쓰지 않습니다. 루프를 직접 구현 해야하는지 여부를 알고 싶었습니다. 팁 고마워.
dreamlax

4
당신은 놀라게 될 것입니다. 나는 ~였다. 내 STL (GCC 및 Dinkumware 모두)에서 std :: copy는 내장 유형으로 호출되는 것을 감지하면 실제로 memcpy로 바뀝니다. std :: fill_n이 memset을 사용하더라도 놀라지 않을 것입니다.
Brian Neal 1

2
아니. 'Value-Initialization'을 사용하여 모든 멤버를 0으로 설정하십시오.
Martin York

24

내장 형식의 배열을 할당하는 방법에는 여러 가지가 있으며 이러한 방법은 모두 올바른지 선택해야합니다.

루프의 모든 요소를 ​​수동으로 초기화

int* p = new int[10];
for (int i = 0; i < 10; i++)
{
    p[i] = 0;
}

std::memset기능 사용<cstring>

int* p = new int[10];
std::memset(p, 0, sizeof(int) * 10);

std::fill_n알고리즘 사용<algorithm>

int* p = new int[10];
std::fill_n(p, 10, 0);

std::vector컨테이너 사용

std::vector<int> v(10); // elements zero'ed

C ++ 0x가 사용 가능한 경우 이니셜 라이저 목록 기능 사용

int a[] = { 1, 2, 3 }; // 3-element static size array
vector<int> v = { 1, 2, 3 }; // 3-element array but vector is resizeable in runtime

1
p = new int [10] ()을 추가하면 전체 목록이 나타납니다.
karsten

@mloskot, "new"를 사용하여 배열을 초기화 한 첫 번째 경우, 참조로 전달하는 방법은 무엇입니까? 내가 사용하는 경우 int array[SIZE] ={1,2,3,4,5,6,7};표기법을, 내가 사용할 수있는 void rotateArray(int (& input)[SIZE], unsigned int k);첫 번째 규칙을 사용하면 내 함수 선언 될 것이다, 무엇을 할 것인가? 어떠한 제안?
Anu

1
예제 std::memset가 잘못되었다는 것이 두렵습니다. 10을 전달하면 바이트 수를 예상하는 것 같습니다 -en.cppreference.com/w/cpp/string/byte/memset 참조하십시오 . (이것이 가능한 경우 저수준 구조를 피해야하는 이유를 잘 보여줍니다.)
Suma

@ 수마 위대한 캐치! 결정된. 이것은 10 년 된 버그의 후보 인 것 같습니다 :-) 예, 귀하의 의견에 동의합니다.
mloskot

7

할당하는 메모리가 유용한 생성자를 가진 클래스 인 경우 new 연산자는 해당 생성자를 호출하고 객체를 초기화 된 상태로 둡니다.

그러나 POD 또는 객체의 상태를 초기화하는 생성자가없는 것을 할당하는 경우 한 번의 작업으로 new 연산자로 메모리를 할당하고 해당 메모리를 초기화 할 수 없습니다. 그러나 몇 가지 옵션이 있습니다.

1) 대신 스택 변수를 사용하십시오. 다음 과 같이 한 단계로 할당하고 기본값을 초기화 할 수 있습니다 .

int vals[100] = {0};  // first element is a matter of style

2) 사용하십시오 memset(). 할당하려는 객체가 POD 가 아닌 경우 memsetting하는 것은 나쁜 생각입니다. 한 가지 구체적인 예는 가상 함수가있는 클래스를 memset하면 vtable을 날려 버리고 객체를 사용할 수없는 상태로 유지하는 것입니다.

3) 많은 운영 체제에는 원하는 것을 수행하는 호출이 있습니다. 힙에 할당하고 데이터를 무언가로 초기화하십시오. Windows 예제는VirtualAlloc()

4) 이것이 가장 좋은 옵션입니다. 메모리를 직접 관리하지 않아도됩니다. STL 컨테이너를 사용하면 한 번의 실패로 모든 것을 할당하고 초기화하는 것을 포함하여 원시 메모리로 할 수있는 모든 작업을 수행 할 수 있습니다.

std::vector<int> myInts(100, 0);  // creates a vector of 100 ints, all set to zero

6

예 :

std::vector<int> vec(SIZE, 0);

동적으로 할당 된 배열 대신 벡터를 사용하십시오. 이점은 배열을 명시 적으로 삭제하지 않아도되며 (벡터가 범위를 벗어날 때 삭제됨) 예외가 발생하더라도 메모리가 자동으로 삭제됩니다.

편집 : 아래 주석을 읽는 것을 귀찮게하지 않는 사람들의 추가 드라이브 바이 다운을 피하려면이 대답이 벡터가 항상 올바른 답 이라고 말하는 것은 아닙니다 . 그러나 "수동으로"배열보다 C ++ 방식이 더 확실합니다.

이제 C ++ 11에는 std :: array가있어 일정한 크기의 배열 (vs 벡터가 자랄 수 있음)을 모델링합니다. 동적으로 할당 된 배열을 관리하는 std :: unique_ptr도 있습니다 (이 질문에 대한 다른 답변에서 답변 된 것처럼 초기화와 결합 할 수 있음). 그것들 중 하나는 IMHO 배열에 대한 포인터를 수동으로 처리하는 것보다 더 C ++ 방식입니다.


11
이것은 실제로 질문에 대답하지 않습니다.
John Knoeller

1
std::vector동적으로 할당 된 배열 대신 항상 사용해야 합니까? 벡터보다 배열을 사용하면 어떤 이점이 있습니까?
dreamlax

1
@ John Knoller : OP는 C ++ 방법에 대해 물었습니다. 벡터는 이것이 C ++ 방법이라고 말하고 싶습니다. 물론 여전히 일반 배열을 요구하고 OP의 상황을 모르는 상황이있을 수 있습니다. OP가 벡터에 대해 알지 못하는 것이 타당 해 보이기 때문에 나는 추측하지 않습니다.
villintehaspam

1
@villintehaspam :이 솔루션이 내 질문에 대답하지는 않지만 제가 취할 경로입니다. Tyler McHenry는 제 질문에보다 직접적으로 답변하며, 어떤 이유로 든 사용할 수없는 사람들에게 특히 도움이됩니다 std::vector.
dreamlax

2
@villintehaspam : 아니요, C ++ 방식이 아닙니다. 그것을하는 Java 방법입니다. vector문맥에 관계없이 어디든지 고집하는 것을 "C ++로 Java 코드 작성"이라고합니다.
AnT

2

std::fill한 가지 방법입니다. 두 개의 반복자와 영역을 채울 값을 가져옵니다. 즉, for 루프는 더 C ++ 방식 일 것입니다.

기본 정수 유형의 배열을 구체적으로 0으로 설정하면 memset눈썹을 올릴 수 있지만 좋습니다. calloc캐스트 때문에 C ++에서 사용하는 것이 약간 불편하지만을 고려하십시오 .

내 부분에서는 거의 항상 루프를 사용합니다.

(나는 사람들의 의도를 추측하는 것을 좋아하지 않지만 std::vector모든 것이 동등하고을 사용하는 것보다 낫다는 것은 사실입니다 new[].)


1

당신은 항상 memset을 사용할 수 있습니다 :

int myArray[10];
memset( myArray, 0, 10 * sizeof( int ));

사용할 수 있음을 이해합니다 memset 하지만 이것이 문제에 접근하는 C ++ 방법인지 확실하지 않습니다.
dreamlax

1
실제로 'C ++ 방식'은 아니지만 원시 배열도 아닙니다.
피트 Kirkham

1
@gbrandt : C 또는 C ++에서 잘 작동하지 않는다고 말하는 것입니다. 유형의 대부분의 값에서 char 또는 unsigned char이 작동합니다. 대부분의 유형의 값이 0 인 경우 작동합니다 (적어도 대부분의 구현에서는). 그렇지 않으면 일반적으로 쓸모가 없습니다.
Jerry Coffin

1
10 * sizeof( *myArray )보다 문서화되고 변경이 방지 10 * sizeof( int )됩니다.
Kevin Reid

1
어쨌든 OP에는 원시 배열이 있으며 memset은 해당 배열을 0으로 만드는 가장 빠르고 쉬운 방법입니다.
Gregor Brandt

-1

일반적으로 동적 항목 목록에는을 사용합니다 std::vector.

일반적으로 코드 영역이 앞으로 어떻게 변할지에 따라 원시 메모리 동적 할당에 memset 또는 루프를 사용합니다.

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