2016-02-15 34 views
0

如何爲現有對象創建包裝類,該類將自動禁止或允許修改包裝對象的數據,具體取決於包裝對象是否提供給具有或不具有const類型限定符的構造函數。如何創建快速const正確的緩衝包裝類C++?

因此,如果包裝類收到(WrappedObj * ptr),那麼它允許設置和獲取方法。如果收到包裝類(const WrappedObj * ptr),那麼在編譯時只允許獲取方法。

問題例如:

我有一個指針來緩衝在有以太網報頭和欲減輕訪問以太網數據是爲了可讀性和通過字節序減少錯誤。

struct ethhdr { 
    uint8_t h_dst[6]; /* destination eth addr */ 
    uint8_t h_src[6]; /* source ether addr */ 
    uint16_t h_proto;  /* packet type ID field */ 
    uint8_t h_data[0]; 
} __attribute__((packed)); 

// My wrapper "view" class, which doesn't really work as expected 
class EtherView { 
public: 
    EtherView(uint8_t *ptr) : mPtr{(ethhdr*)ptr} {} 
    EtherView(const uint8_t *ptr) : mPtr{(ethhdr*)ptr} {} 

    /* SET METHODS */ 
    void setProtocol(uint16_t proto) { 
     mPtr->h_proto = htons(proto); 
    } 
    /* ........ */ 

    /* CONST GET METHODS */ 
    uint16_t protocol() const { 
     return ntohs(mPtr->h_proto); 
    } 
    /* ........ */ 

private: 
    ethhdr *mPtr; 
}; 

int main() { 
    uint8_t fakeBuffer[128]; 
    EtherView ethView(fakeBuffer); 
    //OK - we want to modify because fakeBuffer isn't const 
    ethView.setProtocol(80); 

    const uint8_t *fakeConstBuff = fakeBuffer; 
    EtherView constEthView(fakeConstBuff); 
    // HERE I WANT COMPILE ERROR, because Wrapper was created with const param 
    constEthView.setProtocol(80); 

    /* I know its possible to define const wrapper: 
    const EtherView constEthView(fakeConstBuff); 
    , but I do not trust to "remember" to do it - it must be automatic. */ 

    return 0; 
} 

正如你可以看到這個包裝提供了安全和重要的快速包裝緩衝區修改/閱讀。我已經測試過,並且它具有相同的性能,就像內聯緩衝區值修改(因爲它們由編譯器內聯)一樣。

可能的(不完美)的解決方案迄今:

1)記得添加常量的包裝類,當常量數據源。

  • 不想「記住」(最終會出錯)

2)讓基類(EthViewConst)的getter和構建只在常量源。然後繼承那個類,它構造在非const源上並且也具有setter函數。如果不存在任何其他解決方案,那麼這可能是「最好」的方式,但是:

  • 確實沒有達到要求。我想有一門課,但如果不可能,那麼它是可以接受的。

3)有一些特殊的Factory,它根據數據源創建const或非const對象。 「僞碼」的例子: [EtherView視圖= EtherView ::創建(緩衝液)],但我似乎無法找到一種方法來做到這一點,是因爲:

  • 動態返回const或非const創建包裝類指針將工作,但不符合要求:它必須是快速的。在這種情況下,這將是巨大的成本。
  • 返回const /非const對象不起作用,因爲「receiver」可以定義非const對象並且通過複製構造會丟失常量
  • 返回引用不能爲非const對象完成(因爲的臨時)。也許有一些黑客的方式?

4).....其他解決方案..... ??

  • 搬家建築?
  • 完美轉發?
  • 模板?
  • constexpr?
  • 預處理 - 不,謝謝
+0

如果您將setter公開,那麼所有保持const的嘗試都變得毫無用處。您可以嘗試在struct const中創建所有字段,並只允許並實現所有必需的構造函數,以確保在初始化時可以填充該結構。 – user3528438

+0

我真的不明白你在做什麼,爲什麼你不能刪除所有的setter函數? – Galik

+1

有些讀物是基本上試圖做的。這些表明你的選擇2是最好的方法,你只需要處理它:(A)https://bytes.com/topic/c/answers/637500-making-constructor-const(B)http ://stackoverflow.com/questions/6936124/why-does-c-not-have-a-const-constructor(C)https://www.reddit.com/r/cpp/comments/2yei1n/the_c_language_standard_and_const_constructors/ – paddy

回答

1

這可能是模板機制的濫用行爲,你的里程將取決於如果產生未使用的模板方法有所不同,如果是這樣,你的鏈接器如何與他們交易。我會說,以下內容很可能不是可移植的,可能是瘋狂的。幸運的是,如果端口不好,你可以隱藏在某些類型別名後面以確保安全。

如果在視圖的可變版本中使用const uint16_t*,或者在視圖的常量版本中使用uint16_t*,則此方法會非常大聲地抱怨。

#include <type_traits> 

struct ethhdr { 
    uint8_t h_dst[6]; /* destination eth addr */ 
    uint8_t h_src[6]; /* source ether addr */ 
    uint16_t h_proto;  /* packet type ID field */ 
    uint8_t h_data[0]; 
} __attribute__((packed)); 


template<typename T, typename U> 
class EtherView { 
public: 
    EtherView(T* ptr) : mPtr{(U*)ptr} {} 

    /* SET METHODS */ 
    void setProtocol(T proto) { 
     mPtr->h_proto = proto; 
    } 

    /* CONST GET METHODS */ 
    T protocol() const { 
     return mPtr->h_proto; 
    } 
private: 
    U *mPtr; 
}; 

using MutableEtherView = EtherView<uint16_t, ethhdr>; 
using ConstEtherView = EtherView<const uint16_t, const ethhdr>; 

int main() { 
    uint8_t fakeBuffer[128]; 
    MutableEtherView ethView(fakeBuffer); 
    ethView.setProtocol(80); 

    const uint8_t *fakeConstBuff = fakeBuffer; 
    ConstEtherView constEthView(fakeConstBuff); 
    MutableEtherView mutView(fakeConstBuff);  // Generates error here 
    constEthView.setProtocol(80);     // Generates error here 

    return 0; 
}