2013-07-09 7 views
1

코드베이스에서 다음 코드를 발견했습니다. 제 동료는 괜찮다고 생각하지만 의심스럽게 UB처럼 보입니다. UB인가요?이 정의되지 않은 동작입니까?

class A { 
    //some stuff 
}; 

class B : public A { 
    int a; 
    int b; 
    int c; 
} 

void foo(std::vector<A>& a) { 

    std::vector<B> b; 
    for(size_t i = 0 ; i < a.size(); ++i){ 
     b.push_back(*(B*)(&a[i])); 
    } 

    //remove some elements from b 

    for(size_t i = 0 ; i < b.size(); ++i){ 
     a.push_back(*(A*)(&b[i])); 
    } 

} 
+0

'* (B *) (& a [i])'는'a [i]'의 메모리 이상으로 데이터를 읽습니다. 마지막 요소는 소유 한 메모리 이외의 데이터를 읽습니다. –

+1

'push_back'은'B'의 복사 의미를 사용하여'A'를 복사합니다. (a, b 또는 c를 복사하지 않는 한) 초기화되지 않은 메모리를 확실히 읽습니다. –

+0

@ LuchianGrigore 이미 dereencing이 UB가 아닌가요? – bennofs

답변

6

이것은 정의되지 않은 동작입니다. 원래 벡터 안에있는 실제 객체는 B이 아닌 A이므로 캐스트가 잘못되어 정의되지 않은 동작이 발생합니다.

이 코드의 가장 일반적인 결과는 잘못된 데이터 (B의 멤버가 벡터의 다음 개체 (있는 경우) 또는 다음 메모리 위치에서 읽음)이거나 충돌 (해당되는 경우 마지막 요소를 될 일이, 원래의 벡터에 예약 여분의 공간과 읽기 보호되는 메모리 페이지로 확장하는 일이 없었다

+0

B의 복사 생성자가 a, b 또는 c를 복사하지 않으면 반드시 필요한가? 그런 다음 할당 된 외부 메모리를 읽을 수 없습니다. (아니, 나는 확실히이 코드를 옹호하지 않는다. 단지 기술적 인 부분에 대해 궁금하다.) –

+3

@JoachimIsaksson : 위의 코드에서 복사 생성자가 암시 적으로 정의되어 복사본을 시도합니다. 다른 경우에는 해당 멤버를 건드리지 않는 복사 생성자를 구현할 수 있지만 그다지 말하기는 어색 할 것입니다 ... 왜 그 멤버는 중요하지 않습니까? 'A' 객체로부터 복사를 지원하고 싶다면'A'를 취하는 생성자를 구현할 수 있습니다. –

+0

기본 복사 생성자에 관한 사실입니다. 고려하지 않았습니다. 'UB'와'HHC' (끔찍한 끔찍한 코드) 사이에 선을 분명히 그려달라고 요청하십시오 :) –

1

짧은 답변 -. 예, 그것은 정의되지 않은 동작입니다

제거. 벡터는이를 더 명확하게 만듭니다.

void foo(A a) { 
    B b; 
    b = *(B*)(&a); 
    a = *(A*)(&b); 
} 

위의 버전은 관련된 메모리 문제와 관련한 버전입니다. 마지막 문 - a에 대한 할당 -이 실제로 유효합니다. 그것은 다형성의 업 스케일이며 실제로 모든 여분의 캐스팅이 필요하지 않습니다. 괜찮습니다 :

a = *&b; 

b에 대한 첫 번째 할당은 정의되지 않았습니다. 불법 다형 다운 캐스트를 시도하고 있습니다. 이것은 무해 할 수 있으며 모든 추가 캐스팅은 컴파일러가이를 받아들이도록 강제 할 것입니다. 그러나 이것은 명확히 정의되지 않은 동작입니다.

일반적으로 C 스타일의 C 스타일 캐스트를 사용하는 경우 문제가 발생합니다. &aB*하지 않기 때문에

b = *(dynamic_cast<B*>(&a)); 

그러나이 런타임에 실패하고 사실, 내 컴파일러는 내가 무엇을하고 있어요 있다는 경고를 제공합니다 낙심의 유형을 시도하는 올바른 방법은 dynamic_cast는 함께

warning: dynamic_cast of 'A a' to 'class B*' can never succeed 
관련 문제