在C(使用gcc)中,我可以声明一个变长结构,如下所示:
typedef struct ProtocolFrame
{
uint8_t op;
uint32_t address;
uint16_t size;
uint8_t payload[0];
} ProtocolFrame;
然后我可以分配不同的框架:
ProtocolFrame *frA;
ProtocolFrame *frB;
frA = malloc(sizeof(ProtocolFrame) + 50);
frB = malloc(sizeof(ProtocolFrame));
在此示例中,frA的有效负载字段大到50个字节,而frB没有有效负载
我可以使用new运算符在C ++中做同样的事情吗?
答案 0 :(得分: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>;
要确定运行时的大小,您可以使用placement-new运算符与std::malloc
合作:
void *buffer = std::malloc(sizeof(ProtocolFrame)+50);
ProtocolFrame *frA = new (buffer) ProtocolFrame;
您还可以在codeproject.com上阅读包含完整示例的this article。
答案 1 :(得分: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分配
编辑:我已经读过你不应该直接调用delete而是析构函数。我认为这可能是一个特定的compliler行为。我没有多少使用新的放置,但是当我这样做时,我调用了删除,它与MSVC ++一起工作正常。所以标准的正确方法似乎是frA-&gt; ~ProtocolFrame();然后删除buf;这看起来很糟糕!我建议你可以阅读它。
答案 2 :(得分: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();
}
};
但这种代码风格非常糟糕。
答案 3 :(得分:1)
在C ++中你有类。 ProtocolFrame
的构造函数不应该得到关于你想要多少payload
的参数吗?
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;
}
}
答案 4 :(得分: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;
}
虽然可能无法通过new
进行现场调整。
答案 5 :(得分:0)
即使是C风格,我认为这是野蛮的代码。
和sizeof()你的结构仍将返回相同的大小。
为什么不将payload
视为普通动态数组?
EDIT2:@Chris哦,我看到有2次调用malloc ...是的效率较低
inline ProtocolFrame * createProtocolFrame(int i)
{
ProtocolFrame * pProto = malloc(sizeof(ProtocolFrame));
pProto->payload = malloc(i * sizeof(uint8_t));
}