2014-09-21 76 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和提升可能嗎?

MessageTypeList tl; 
tl.append(Message1); 
tl.append(Message2); 
void UnSerialize(MessageTypeList tl, int messageId, void* data) { 
{ 
    foreach(type t : tl) { 
     if (t::id == MessageId) { 
      t instance = new t; 
      memcpy(t, data, sizeof(t)); 
      instance.dump(); 
      delete instance; 
     } 
    } 
} 
+0

你的假設'UnSerialize'相當於到'void UnSerialize(MessageTypeList tl,int messageId,void * data){}'。它沒有副作用,除了泄漏的記憶。對於這個問題,最初的'void UnSerialize(int messageId,void * data)'也是如此。所有分配的內存應該發生什麼? – 2014-09-21 01:23:42

+0

在switch語句中創建消息後,消息會發生什麼變化?如果你只是在做一個memcpy,爲什麼信息的類型很重要? (類的memcpy可能非常糟糕)。 – 2014-09-21 01:28:19

+1

你的代碼無效,'memcpy'正在複製一個指針的大小。 'new Message1;'不適用於不完整的類型。你顯然沒有理由使用動態分配。 – 2014-09-21 03:56:33

回答

-1

有一些方法可以表示對的列表(type,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 2014-09-21 14:22:03

+0

@Quest,它應該適用於大多數應用程序,但必須注意確保每個'T'的'data'正確對齊。 – 2014-09-27 01:01:55

1

我不知道你想做的事,但如果你只是想打電話從Message1Message2結構一個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指針,因此虛函數調用將不起作用。 – 2014-09-27 01:05:17