2012-05-07 3 views
1

나는 다음과 같은 코드가 있습니다게재 위치가 새로운 값으로 메모리가 제로가됩니까?

struct foo {}; 
void bar(foo *d) { 
    new(d) foo(*d); 
} 

이 표현 new(d) foo(*d) 개체를 떠나지 않습니다는 d 변화가 가리키는? 더 구체적으로 말하면, 클래스 foo과 그 안에 재귀 적으로 포함 된 모든 객체가 사소한 복사 생성자 만 갖는 경우 위의 내용이 참일 경우 new(d) foo(*d)*d으로 변경되지 않습니까? 사실이 아닌 상황은 new이 먼저 복사 생성자를 호출하기 전에 메모리를 초기화합니다. C++ 언어에 이와 같은 절이 있습니까?

편집 : 누군가가 이것을하고 싶어하는 이유는 드뭅니다. 예를 들어 CPU 메모리에서 GPU 메모리로 주소 공간을 통해 객체를 복사하는 것을 고려하십시오. 한 가지 해결책은 객체의 바이트 단위로 작업하는 것입니다. 이것은 많은 경우에 적용됩니다. 클래스에 가상 메소드가있는 경우 바이트 단위 복사는 vtable 포인터를 복사 한 다음 일부 CPU 메모리를 가리 킵니다. 위의 식을 new(d) foo(*d) 개체에 사용하여 컴파일러에서 vtable 포인터를 다시 설정하도록 할 수 있습니다.

+0

http://stackoverflow.com/questions/2204176/how-to-initialise-memory- with-new-operator-in-c – m0skit0

+0

당신이 이것을했다면 다소 혼란스러운 결과를 기대할 수 있습니다. –

+0

왜 그럴까요? 비 - 배치 - '새로운 것'이 메모리를 제로로 만들 것을 기대 하시겠습니까? 생성자에서 명시 적으로 초기화되지 않은 POD 멤버에는 가비지 값이 있습니다. – jamesdlin

답변

0

아직 새로 초기화되지 않은 개체에 대해 설정된 메모리에서 생성자를 실행하면됩니다. 대신에 생성자를 수동으로 호출하면 얻을 수있는 것보다 더 많은 것도 아무것도하지 않습니다 (가능하지는 않지만).

+0

첫 문장은 오해의 소지가 있습니다. "이미 존재하는 객체"가 될 필요는 없으며, 일반적으로 정의되지 않은 동작이며, 어떤 경우에도 객체는 생성자가 시작될 때까지 기존 객체를 중단합니다. 오히려, placement-new는 주어진 메모리 위치에 * 객체를 만듭니다. –

+0

Meh. 객체로 던지면 객체입니다. 그래서 그 메모리를 할당하고 객체 유형의 포인터에 할당하면 객체입니다. 아직 초기화되지 않은 객체입니다. 정확성을 위해 게시물을 업데이트했습니다. –

+0

@ MahmoudAl-Qudsi : 실제로 건축되지 않고 파괴되지 않았다면 건축물과 파괴 이후의 기억의 블록입니다. –

0

개체 자체의 복사본 생성자를 복사 원본으로 호출한다는 점에 유의하십시오. 나는 이것이 단순히 열매가 될 것을 기대합니다. 누가 알아. 나는 표준에서 아무것도를 기대하게하는 어떤 것도 보지 못합니다.

1

이것은 정의되지 않은 동작이라고 생각합니다. 객체가 저장된 메모리가 다른 용도로 사용되면 객체의 수명이 끝납니다. this 포인터가 d 인 복사 생성자를 입력하면 원본 개체가 존재하지 않게되고 (언어와 관련하여) 복사 생성자에 매달린 참조가 생깁니다.

~foo()에 효과가있는 상황이 더 쉽습니다.이 경우 아직 정의되지 않은 동작이있는 또 다른 이유가 있습니다.

+0

'd'가 가리키는 이유 때문에 유효 객체를 가리키고'd'가 미처리 메모리를 가리키면 정의되지 않은 동작입니다. 복사 생성자에 대한 인자로 사용되기 때문에 여전히 UB입니다. –

+0

@ DavidRodríguez-dribeas : 맞아. 나는'* d'가 유효한 객체라고 가정했다; 그렇지 않으면 게임이 바로 끝나고 200 달러를 모으지 않고 감옥에갑니다. –

+0

@KerrekSB 즉, in-place new가 초기화되지 않은 메모리에서만 사용되도록 의도 된대로 "적절한"코드에 대한 잘못된 가정이됩니다. –

1

게재 위치가 메모리에서 0을 벗어나는 지 여부에 상관없이, 생성자가 수행하는 모든 작업을 수행하는 적절한 생성자를 호출하기 만합니다. 이는 생성 방법에 따라 메모리를 제로로 만들거나 생성하지 않을 수 있습니다. 이 특별한 경우 복사 생성자를 사용하고 있습니다.

제시 한 코드에서 정의되지 않은 동작입니다. d은 올바른 개체를 가리키거나 나타내지 않습니다. 유효한 객체를 참조하는 경우 이미 생성 된 객체에서 생성자를 호출합니다. 이는 객체에 사소한 소멸자가없는 경우 정의되지 않은 동작입니다. 이전에 초기화되지 않은 경우 (즉, foo 객체를 참조하지 않는 경우) 복사 할 때 정의되지 않은 동작입니다.

+0

"이미 초기화 된 객체에서 생성자를 호출하는 것"이 ​​명백히 잘못되었다고 생각하지 않습니다. 소멸자가 아무 효과가 없다면, 나는 그것이 괜찮다고 믿습니다. 3.8 (1) 참조. –

+0

새로운 배치가 메모리를 제로화하지 않는다는 주장을 제외하고는 말한 모든 것에 동의합니다. 한 가지 방법으로 요구 사항을 만드는 표준을 볼 수 없으며 많은 구현이 메모리를 제로로 처리합니다. – janm

0

성능 문제를 조사하는 동안이 질문을 만났습니다. 큰 버퍼가 포함 된 객체에 새로운 배치를 사용하는 일부 코드는 예기치 않게 느려졌습니다. 그 이유는 배치 new가 생성자를 호출하기 전에 메모리를 초기화하지 못하기 때문입니다.

내 표준 읽기는 다른 대답과 일치합니다. 컴파일러는 특별히 필요한 작업이 필요하지 않습니다.

그러나 gcc 4.9, gcc 5.3, clang 3.4, clang 3.8 및 Apple clang 모두 배치 새 사례에서 메모리를 제로로 처리하는 것으로 보입니다.어셈블러 출력을 검사하면 생성자를 호출하기 전에 memset에 대한 명시 적 호출이 있습니다. 스택으로 구성된 객체는 0으로 초기화되지 않으므로 작업을 수행하는 생성자가 아닌 것 같습니다.

Dignus Systems/C++ for z/OS에서 어셈블러 출력을 검사하면 아마도 비슷한 기능을하는 라이브러리 기능을 호출하는 것처럼 보입니다.

So : 새로운 배치는 메모리를 제로화 할 수 있으며 많은 구현이 메모리를 제로화하는 것처럼 보입니다.

예 테스트 케이스 (FreeBSD의 연타에 3.4)

#include <new> 
#include <cstdint> 
#include <stdio.h> 

struct Test { 
    char b[4]; 

    void show(char const* prefix) { 
     for (unsigned i = 0; i < sizeof(b); ++i) 
      printf("%s index %d: %d\n", prefix, i, b[i]); 
    } 
}; 

int main() 
{ 
    char* p = new char[sizeof(Test)]; 

    for (unsigned i = 0; i < sizeof(Test); ++i) 
     p[i] = 'Q'; 

    Test* t1 = new(p) Test(); 
    Test t2; 

    t1->show("t1"); 
    t2.show("t2"); 
} 

출력 예 :

t1 index 0: 0 
t1 index 1: 0 
t1 index 2: 0 
t1 index 3: 0 
t2 index 0: 51 
t2 index 1: -1 
t2 index 2: 3 
t2 index 3: 1 

관련 문제