2014-09-21 3 views
-1

이진 파일에서로드 된 대량의 메모리를 보편화하고 메시지 ID를 알고 싶습니다. 각 메모리 덩어리에 대해 새 인스턴스를 만들어야합니다. 이 작업을 수행하는 가장 좋은 방법은 무엇입니까?이런 종류의 스위치 케이스를 제거하는 방법은 무엇입니까?

현재 상황은 다음과 같은 스위치 케이스에 새로 추가 된 각 메시지 유형을 추가해야합니다.

struct Message1; 
struct Message2; 

void UnSerialize(int messageId, void* data) { 
    switch (messageId) { 
    case MESSAGE1: 
     Message1* m1 = new Message1; 
     std::memcpy(m1, data, sizeof(Message1)); 
     m1.dump(); 
     delete m1; 
     break; 
    case MESSAGE2: 
     Message2* m2 = new Message2; 
     std::memcpy(m2, data, sizeof(MESSAGE2)); 
     m2.dump(); 
     delete m2; 
     break; 
    default: 
     std::cout << "Unknown Message Type."; 
     break; 
    } 
} 

내가 C++에서 다음과 같이 작성할 수 있습니까? C++ 11 및 부스트없이 가능합니까?

+0

는'UnSerialize'는 해당 가상 귀하를 'UnSerialize (MessageTypeList tl, int messageId, void * data) {}'를 무효화합니다. 메모리 누출 이상의 부작용이 없습니다. 그 점에 대해서는 원래의'void UnSerialize (int messageId, void * data)'도 마찬가지였습니다. 그 모든 할당 된 기억에 어떤 일이 일어나기로되어 있습니까? –

+0

메시지가 switch 문에서 만들어진 후 어떻게됩니까? 당신이 memcpy를하고 있다면, 왜 메시지의 유형이 중요합니까? (클래스의 memcpy는 매우 나쁠 수있다). –

+1

코드가 유효하지 않습니다.'memcpy'는 포인터의 크기를 복사하고 있습니다. 'new Message1; '은 불완전한 타입들에서도 작동하지 않습니다. 분명히 이유없이 동적 할당을 사용합니다. –

답변

-1

쌍 (유형, id) 목록을 표현하고 각 유형 또는 ID에 대해 원하는 동작을 구현하는 몇 가지 방법이 있습니다. 그러나 스위치는 여전히 매우 좋은 접근 방법이라고 생각합니다. 모든 접근법에서 모든 유형을 정리하여 나열해야하지만 각 사례 내부의 코드를 템플릿 함수로 사용하십시오. 나는 각각의 경우 내부 코드에 대한 다른 구현을 제안했습니다

template <class T> 
void UnSerialize(void* data) { 
    static_assert(std::is_trivially_copyable<T>::value, 
        "Message class is not trivally copyable"); 
    T message; 
    memcpy(&message, data, sizeof(T)); 
    message.dump(); 
} 

void UnSerialize(int messageId, void* data) { 
    switch (messageId) { 
    case MESSAGE1: 
     UnSerialize<Message1>(data); 
     break; 
    case MESSAGE2: 
     UnSerialize<Message2>(data); 
     break; 
    default: 
     std::cout << "Unknown Message Type."; 
     break; 
    } 
} 

참고 :

  • 없음 동적 할당 메시지는 함수에 로컬 변수에 할당됩니다.
  • memcpy이 예상대로 작동 할 것이라는 정적 어설 션을 추가했습니다.

또 다른 접근법은 switch을 전혀 피하기 위해 가상 메서드로 도우미 클래스의 인스턴스와 ID 쌍의 배열을 만드는 것입니다. 각 인스턴스는 가상 메소드를 구현하는 파생 된 템플릿 클래스의 코드가 될 수 있습니다. 그런 다음 배열을 정적으로 빌드해야합니다 (도우미 클래스에 대한 포인터를 보유하기 위해 std::unique_ptr을 사용하는 것이 좋습니다).

해당 배열을 쓰는 것은 switch을 작성하는 것과 매우 유사하며 코드를 읽기가 더 어렵게 만듭니다.

+1

UnSerialize 함수에서 한 줄짜리 코드는 어떨까요?'((T *) data) -> dump();' – Quest

+0

@Quest가 대부분의 응용 프로그램에서 작동하지만'T'마다 '데이터'가 제대로 정렬되도록주의를 기울여야합니다. –

1

나는 당신이하고 싶은 일에 대해 잘 모르겠어요하지만 당신은 단지 Message1 또는 Message2 구조체에서 Dump 함수를 호출 할 경우, 당신은 다음을 수행 할 수

struct BaseMessge 
{ 
    virtual void Dump() = 0; 
}; 
struct Message1 : public BaseMessage 
{ 
    void Dump() 
    { 
     //Your code 
    } 
}; 
struct Message2 : public BaseMessage 
{ 
    void Dump() 
    { 
     //Your code 
    } 
}; 

void UnSerialize(BaseMessage *Message) 
{ 
    Message->Dump(); 
} 
+0

'UnSerialize'가 어떤 타입에 임의로 매핑 된 정수와 바이트 배열에 대한 포인터를 실제로 받기 때문에 이것이 어떻게 문제를 해결할 지 모르겠습니다. 함수 이름과 정수 매개 변수의 필요성을 감안할 때이 바이트 배열에는 vtable 포인터를 제대로 설정할 수 없으므로 가상 함수 호출이 작동하지 않습니다. –

관련 문제