2010-12-23 74 views
5

在C(使用gcc)我可以聲明的可變長度結構如下面零長度數組的結構體:ALLOC使用新

typedef struct ProtocolFrame 
{ 
    uint8_t  op; 
    uint32_t  address; 
    uint16_t  size; 
    uint8_t  payload[0]; 
} ProtocolFrame; 

然後我可以ALLOC不同幀:

ProtocolFrame *frA; 
ProtocolFrame *frB; 

frA = malloc(sizeof(ProtocolFrame) + 50); 
frB = malloc(sizeof(ProtocolFrame)); 

在這個例子frA有一個大於50字節的有效載荷字段,而frB沒有有效載荷

我可以使用new運算符在C++中做同樣的事嗎?

回答

9
template<size_t s> 
struct ProtocolFrame 
{ 
    uint8_t  op; 
    uint32_t  address; 
    uint16_t  size; 
    uint8_t  payload[s]; 
} ProtocolFrame; 

// specialize for no payload 
template<> 
struct ProtocolFrame<0> 
{ 
    uint8_t  op; 
    uint32_t  address; 
    uint16_t  size; 
} ProtocolFrame; 

ProtocolFrame<50> *frA = new ProtocolFrame<50>; 
ProtocolFrame<0> *frB = new ProtocolFrame<0>; 

要決定什麼是在運行時,你可以使用合作投放新的運營商,std::malloc大小:

void *buffer = std::malloc(sizeof(ProtocolFrame)+50); 
ProtocolFrame *frA = new (buffer) ProtocolFrame; 

你可以是包含完整的樣本codeproject.com也看了this article

+2

這並不完全相同,因爲通過使用malloc,他有一個動態大小的擴展,而這是靜態大小。 – Puppy 2010-12-23 10:26:26

+0

你不一定需要`std :: malloc`。你可以寫`新字符[sizeof(ProtocolFrame)+ 50];`但我不知道這是否保證對齊。 – 2010-12-23 10:32:07

+2

@Chris:`:: operator new(sizeof(ProtocolFrame)+50)`保證對齊。 – 2010-12-23 10:42:34

0

即使在C風格,我認爲這是野蠻代碼。

和sizeof()你的結構仍然會返回相同的大小。

爲什麼不把​​作爲一個正常的動態數組?

編輯:我喜歡基里爾五Lyadvinsky的回答

EDIT2:@克里斯哦,我看到有2調用malloc ......是的,它是效率較低

inline ProtocolFrame * createProtocolFrame(int i) 
{ 
    ProtocolFrame * pProto = malloc(sizeof(ProtocolFrame)); 
    pProto->payload = malloc(i * sizeof(uint8_t)); 
} 
1

通常情況下,你會使用std :: vector。

class ProtocolFrame { 
    // Invokes undefined behaviour if stuff is not POD. 
    struct stuff { 
     stuff(uint8_t lop, uint32_t laddress, uint16_t lsize) 
      : op(lop), address(laddress), size(lsize) { 
     } 
     uint8_t op; 
     uint32_t address; 
     uint16_t size; 
    }; 
    std::vector<uint8_t> payload; 
public: 
    ProtocolFrame(int payloadsize, uint8_t op, uint32_t address, uint16_t size) 
     : payload(size + sizeof(stuff)) { 
     new (&payload[0]) stuff(op, address, size); 
    } 
    // other methods here 
    uint32_t GetAddress() { 
     return ((stuff*)&payload[0])->address; 
    } 
    uint16_t GetSize() { 
     return ((stuff*)&payload[0])->size; 
    } 
    uint8_t GetOp() { 
     return ((stuff*)&payload[0])->op; 
    } 
    std::vector<uint8_t>::iterator begin() { 
     return payload.begin() + sizeof(stuff); 
    } 
    std::vector<uint8_t>::iterator end() { 
     return payload.end(); 
    } 
}; 

雖然這種風格的代碼是非常可怕的。

2

使用放置新

char *buf = new char[sizeof(ProtocolFrame) + 50]; //pre-allocated buffer 
ProtocolFrame *frA = new (buf) ProtocolFrame; //placement new 

// STUFF 

frA->~ProtocolFrame(); 
delete [] buf; 
當你刪除FRA它會調用析構函數ProtocolFrame和免費BUF分配

編輯

:我看過,你不應該調用刪除,但析構函數直接。我認爲這可能是一個compliler特定的行爲。我沒有使用過多的貼圖,但是當我這樣做時,我調用了刪除,並且它在MSVC++中運行良好。所以標準的正確方法似乎是frA->〜ProtocolFrame();然後刪除buf;這看起來很可怕!我建議你可能想閱讀它。

1

在C++中你有類。 ProtocolFrame的構造函數是否應該得到一個參數,以表示您需要多少個​​?

struct ProtocolFrame { 
    uint8_t  op; 
    uint32_t  address; 
    uint16_t  size; 
    uint8_t  *payload; 

    public: 
     ProtocolFrame (int size) { 
      payload = new uint8_t [size]; 
     } 

     ~ProtocolFrame() { 
      delete [] payload; 
     } 
} 
1

不知道這是否是感興趣的是,但你可以重載operator new做到這一點。這適用於G ++ 4.0。1(我不知道怎麼「好」是,隨意編輯和改進):

#include <cstddef> 

template <typename T> 
class test { 
    public: 
    std::size_t len; 
    T arr[1]; 

    void *operator new(std::size_t s, std::size_t a); 

    test(const T& f) { fill(f); } 
    test(); 

    private: 
    void fill(const T& f) { for(std::size_t i = 0; i < len; i++) arr[i] = f; } 
}; 

template <typename T> 
void *test<T>::operator new(std::size_t s, std::size_t a) 
{ 
    void *p = ::operator new(s + (a - 1) * sizeof(T)); 
    // this is bad and we shouldn't do this here blah blah blah 
    // but I don't know how to pass a to the ctor so this is what I did 
    ((test<T> *)p)->len = a; 
    return p; 
} 

的使用是不是太可怕之一:

#include <iostream> 

int main() 
{ 
    test<char> *c = new (10) test<char>('c'); 
    std::cout << c->arr[3] << std::endl; 
    delete c; 
    return 0; 
} 

雖然調整-IN-地方可能不可能通過new