2013-07-14 1 views
0

개체 조각이없는 벡터에 파생 클래스를 저장하려고합니다. 나는 을 하루의 대부분을 열심히보고 있었고 그것이 작동하게 만드는 방법을 알아 내지 못했습니다. 내가 파생 된 객체에 대한 포인터를 저장하는 것이 좋습니다. 실제로 실제 객체를 저장하는 것이 좋습니다. 나는 그것을 작동시키지 못했지만,이 객체들을 에 추가하여 벡터가 범위를 벗어나는 전에 객체가 범위를 벗어날 수 있도록합니다. 그래서, 그런 해결책은 어쨌든 일할 것이라고 생각하지 않습니다. 또 다른 해결책은 기본 클래스를 추상화하는 것이지만 중 하나는 작동하지 않는다는 것을 의미합니다. 나는 대입 연산자와 복사를 무시하는 것에 대해 읽었지 만, 그들은 보통의 할당 연산자와 noraml 복사 생성자와 다른 것을 끝내지는 않았다고 생각하지 않는다. 나는 가상의 할당 연산자를 사용해도 성공하지 못했습니다. 아래는 제가 작업 한 예입니다. . "vec.emplace_back (& derivedEvent);" 기본 메서드 의 문을 사용하면 벡터에 기본 클래스가 추가됩니다. 그 직후에 객체는 범위를 벗어나 파생 된 Event의 데이터를 더 이상 포함하지 않습니다. 나는 시도한 무엇이든이 부정확하게 행해질지도 모르는 아직도 프로그램에 아주 새롭다.개체 조각화, 범위를 벗어난 벡터 요소

#include <string> 
#include <vector> 
//////////////////////////////////////////////////////////////////////////////// 
class CBaseEvent { 
protected: 
    CBaseEvent(){} 
    std::string m_strBeginning; 
    std::string m_strEnd; 
public: 
    CBaseEvent(std::string strBeginning, std::string strEnd) 
    : m_strBeginning(strBeginning), m_strEnd(strEnd){} 
}; 
//////////////////////////////////////////////////////////////////////////////// 
class CDerivedEvent : public CBaseEvent { 
private: 
    CDerivedEvent(){} 
    std::string m_strMiddle; 
public: 
    CDerivedEvent(
     std::string strBeginning, 
     std::string strMiddle, 
     std::string strEnd) 
     : CBaseEvent(strBeginning, strEnd), 
     m_strMiddle(strMiddle){} 
}; 
//////////////////////////////////////////////////////////////////////////////// 
int main() { 
    std::vector<std::shared_ptr<CBaseEvent>> vec; 
    if (true) { 
     CDerivedEvent derivedEvent = CDerivedEvent("1", "2", "3"); 
     vec.emplace_back(&derivedEvent); 
    } 
    return 0; //CRASH: possible corruption of the heap 
} 
+4

는'나는 벡터가 이해가되지 않습니다 scope'의 외출하기 전에 개체가 범위의 외출 발생합니다 같은 방법으로 벡터에 이러한 개체를 추가 할. 벡터에서 요소를 지우려면'std :: vector :: erase'를 사용하십시오. –

답변

1

당신은 스택과의 범위 안에 객체를 생성하는 문장은, 그것은 그 범위를 벗어나 일단 개체가 더 이상 존재하지 않을 경우, 그리고 share_ptr는 벡터의 외출에 의해 파괴 될 때 더 이상 존재하지 않는 객체를 파괴하려고하기 때문에 프로그램이 충돌 할 주요 함수의 범위.

이 :

if (true) { 
     CDerivedEvent derivedEvent = CDerivedEvent("1", "2", "3"); 
     vec.emplace_back(&derivedEvent); 
    } 

은 다음과 같아야합니다

if (true) { 
     CDerivedEvent* derivedEvent = new CDerivedEvent("1", "2", "3"); 
     vec.emplace_back(derivedEvent); 
    } 

이 예상대로 그것은 작동해야하지만 Jhon 퍼디 아래의 코멘트에 말했듯이,이 더 appropiate 것 :

int main() 
{ 
    std::vector<std::unique_ptr<CBaseEvent> > vec; 

    vec.push_back(std::unique_ptr<CBaseEvent>(new CDerivedEvent("1", "2", "3"))); 

    return 0; 
} 
+0

더 나은 점은 요소 수명을 관리하기 위해'vector <'['unique_ptr'] (http://en.cppreference.com/w/cpp/memory/unique_ptr)'>을 사용하는 것입니다. –

+0

예, CBaseEvent 객체에 대한 참조가 하나뿐이기 때문에 vector >가 더 적합합니다. – AngelCastillo

+0

단순히 포인터를 뒤로 밀기보다는 뒤집어서 무엇을 얻을지 확신하지 못합니다. –

1

내가 좋아하는 것

std::vector<std::unique_ptr<CBaseEvent> > vec; 

AngelCastillo에서 많이 사용하는 접근 방식이지만 그 중 하나만 잘못되었습니다.

std::unique_ptr<CBaseEvent>(new CDerivedEvent(blah))CBaseEvent* 포인터를 통해 CDerivedEvent 유형의 개체를 삭제할 수 있습니다. CBaseEvent에는 가상 소멸자가 없습니다 (심지어는 다형성이 아닙니다), 이것은 정의되지 않은 동작입니다.

는 Deleter가 내부 내부적 타입 정보를 보존 std::shared_ptr를 사용하여 가상 소멸자 또는
  • 를 첨가하거나

    • 의해 고정 될 수있다.

      std::vector<std::shared_ptr<CBaseEvent> > vec; 
      vec.push_back(std::make_shared<CDerivedEvent>(whatever)); 
      
  • +0

    우수 답변. 모든 종류의 고풍스런 혼란을 불러 일으키는'std :: make_unique'와 함께 그 전체 안에 남겨진 것은 부끄러운 C++ 11입니다. – sehe

    +0

    답장을 보내 주셔서 감사합니다. 매우 도움이되었습니다. 내가 제안한대로 가상 소멸자를 만들었습니다. 나는 dynamic_cast를 사용한 후에 벡터에 저장된 CDerivedEvent에 접근 할 수 있었다. – user2581475