2013-05-15 1 views
4

은 msvc에서 mingw로 일부 라이브러리를 이동하기 시작했으며 배열의 업 캐스팅 된 객체를 삭제하려고 할 때 msvc의 매우 흥미로운 동작을 발견했습니다. 즉, msvc는 약간의 어두운 마법을 사용합니다. (그렇게하는 것을 좋아하는 것 같습니다.) 그리고 벨로우즈 코드는 mingw (4.7.2 (크래시.)에서 정상적으로 실행됩니다. 나는 mingw가 올바르게 실행되고 있고 msvc 부두가 침대 버그기본 포인터로 업 캐스팅 된 객체 배열을 삭제합니다

코드 :. MSVC에서

#include <iostream> 

class foo{ 
    static int idgen; 
protected: 
    int id; 
public: 
    foo(){ 
     id = idgen++; 
     std::cout << "Hello (foo - "<<id<<")"<<std::endl; 
    } 
    virtual ~foo(){ 
     std::cout << "Bye bye (foo - "<<id<<")"<<std::endl; 
    }; 
}; 

int foo::idgen = 0; 


class bar: public foo{ 
    double some_data[20]; 
public: 
    bar(){ 

    std::cout << "Hello (bar - "<<id<<")"<<std::endl; 
} 
    ~bar(){ 
     std::cout << "Bye bye (bar - "<<id<<")"<<std::endl; 
    } 
}; 

int main() 
{ 
    const unsigned int size = 2; 
    foo** arr = new foo*[size]; 
    { 
     bar* tmp = new bar[size]; 
     for(int i=0; i<size; i++) 
     { 
      arr[i] = &(tmp[i]); //take address of each object 
     } 
    } 

    delete [] arr[0]; //take address of first object, pointer is same as tmp. This also crashes mingw 
    delete [] arr; 

} 

출력 2010

Hello (foo - 0) 
Hello (bar - 0) 
Hello (foo - 1) 
Hello (bar - 1) 
Bye bye (bar - 1) 
Bye bye (foo - 1) 
Bye bye (bar - 0) 
Bye bye (foo - 0) 

그리고와 Mingw이 (파괴에 추락)

Hello (foo - 0) 
Hello (bar - 0) 
Hello (foo - 1) 
Hello (bar - 1) 

내 질문은 올바른 해결 방법은 무엇입니까? 내가 관여 단지 모든 가능한 클래스로 다운 캐스트하려고 노력하고 downcasted 포인터에 삭제 작업을 호출 해낸 현재 hackfix :

if(dynamic_cast<bar*>(arr[0]) != 0) 
    delete [] dynamic_cast<bar*>(arr[0]); 

는 라이브러리를 재 설계 이외에 (그것이 나의 더 나은 방법이없는가요)? delete 연산자

관한 표준 규격
+0

http://ideone.com/NfbF3n#view_edit_box

당신은 ('foo'의 dtor 참조) 기본 클래스에 그는 하나가 –

+0

@RonDahlgren를 가상 소멸자가 필요합니다. – Steve

+0

와우. 나는이 눈 가리개를 꺼야한다. -/ –

답변

4

, 제 5.3.5 항 3 :

... 제 2 대안에서, 객체의 동적 유형 경우 (배열 삭제) 삭제 될 정적 유형이 정적 유형과 다르면 동작이 정의되지 않습니다.

그래서 실제로, 당신은이 경우 비주얼 C++의 부드러운 동작에 의존하고 배열 delete 운영자에게 기본적으로 현재 상황에서 동적 캐스팅을 의미한다 올바른 유형의 포인터를 제공하려고해서는 안된다.

벡터 인스턴스를 사용하여 하나씩 할당 된 상영 된 객체를 저장하면이 문제를 피할 수 있습니다.

+0

훌륭하다. 까다로운 버그! – Honf

1

gcc 4.7.2는 여기에있는 간단한 예제에서도 실패합니다 -> ideone.com/z876QX#view_edit_box 따라서 가상 소멸자가 배열 인 경우 가상 소멸자를 사용할 수 없습니다. 당신은 당신이 delete 대신 delete[] 사용할 수 포인터의 배열을 사용하는 경우

const unsigned int size = 2; 
foo* test = new bar[size]; 
delete[] test; 

그러나, 당신은 도망.

const int size = 5; 
foo *test[size]; 
for(int i = 0; i < size; ++i) 
    test[i] = new bar; 
for(int i = 0; i < size; ++i) 
    delete test[i]; 
관련 문제