当前位置:  开发笔记 > 编程语言 > 正文

变量大小的Struct C++

如何解决《变量大小的StructC++》经验,为你挑选了3个好方法。

这是在C++中制作可变大小结构的最佳方法吗?我不想使用vector,因为初始化后长度不会改变.

struct Packet
{
    unsigned int bytelength;
    unsigned int data[];
};

Packet* CreatePacket(unsigned int length)
{
    Packet *output = (Packet*) malloc((length+1)*sizeof(unsigned int));
    output->bytelength = length;
    return output;
}

编辑:重命名变量名称和更改的代码更正确.



1> bk1e..:

关于你在做什么的一些想法:

使用C风格的可变长度struct idiom允许您为每个数据包执行一次免费存储分配,这是struct Packet包含a时所需数量的一半std::vector.如果您分配一个非常大的数量的数据包,然后进行一半的自由存储分配/释放操作很可能是显著.如果您还在进行网络访问,那么等待网络所花费的时间可能会更加重要.

该结构表示数据包.您是否计划直接从套接字读取/写入struct Packet?如果是这样,您可能需要考虑字节顺序.您在发送数据包时是否必须从主机转换为网络字节顺序,反之亦然?如果是这样,那么您可以在可变长度结构中对数据进行字节交换.如果将其转换为使用向量,则编写用于序列化/反序列化数据包的方法是有意义的.这些方法会将其转移到连续缓冲区或从连续缓冲区转移,并考虑字节顺序.

同样,您可能需要考虑对齐和包装.

你永远不能继承Packet.如果你这样做,那么子类的成员变量将与数组重叠.

而不是mallocfree,你可以使用Packet* p = ::operator new(size)::operator delete(p),因为它struct Packet是一个POD类型,并且目前不会受益于其默认构造函数及其析构函数被调用.这样做的(潜在)好处是全局operator new使用全局新处理程序和/或异常处理错误,如果这对您很重要.

可以使变长度结构惯用法与new和delete运算符一起使用,但不是很好.您可以operator new通过实现创建一个采用数组长度的自定义static void* operator new(size_t size, unsigned int bitlength),但您仍然需要设置bitlength成员变量.如果使用构造函数执行此操作,则可以使用稍微冗余的表达式Packet* p = new(len) Packet(len)来分配数据包.相比于使用全局我看到的唯一的好处operator newoperator delete将是你的代码的客户端可以只调用delete p代替::operator delete(p).将分配/释放包装在单独的函数中(而不是delete p直接调用)只要正确调用它们就可以了.



2> Nils Pipenbr..:

如果您从未添加构造函数/析构函数,则使用malloc/free进行分配的赋值运算符或虚函数是安全的.

它在c ++圈子中不受欢迎,但我认为如果你在代码中记录它就可以使用它.

对您的代码的一些评论:

struct Packet
{
    unsigned int bitlength;
    unsigned int data[];
};

如果我记得正确声明一个没有长度的数组是非标准的.它适用于大多数编译器,但可能会给你一个警告.如果要符合要求,请声明长度为1的数组.

Packet* CreatePacket(unsigned int length)
{
    Packet *output = (Packet*) malloc((length+1)*sizeof(unsigned int));
    output->bitlength = length;
    return output;
}

这可行,但您不考虑结构的大小.将新成员添加到结构后,代码将中断.最好这样做:

Packet* CreatePacket(unsigned int length)
{
    size_t s = sizeof (Packed) - sizeof (Packed.data);
    Packet *output = (Packet*) malloc(s + length * sizeof(unsigned int));
    output->bitlength = length;
    return output;
}

并在数据包结构定义中写入注释,数据必须是最后一个成员.

顺便说一句 - 用一次分配来分配结构和数据是一件好事.您可以通过这种方式将分配数量减半,并且还可以改善数据的局部性.如果分配大量软件包,这可以提高性能.

不幸的是,c ++并没有提供一个很好的机制来做到这一点,所以你经常在现实世界的应用程序中得到这样的malloc/free hacks.



3> Martin York..:

这没关系(并且是C的标准做法).

但这对C++来说不是一个好主意.
这是因为编译器会自动为您生成一整套其他方法.这些方法不明白你有欺骗行为.

例如:

void copyRHSToLeft(Packet& lhs,Packet& rhs)
{
    lhs = rhs;  // The compiler generated code for assignement kicks in here.
                // Are your objects going to cope correctly??
}


Packet*   a = CreatePacket(3);
Packet*   b = CreatePacket(5);
copyRHSToLeft(*a,*b);

使用std :: vector <>它更安全,工作正常.
我也打赌它会在优化器启动后与您的实现一样高效.

或者,boost包含一个固定大小的数组:http:
//www.boost.org/doc/libs/1_38_0/doc/html/array.html


如果我使用矢量,那么长度成员不会是不连续的吗?
他担心会有第二次分配:new vector (50); 将导致两个分配:一个用于矢量对象,另一个用于由矢量对象维护的50个int的数组.
推荐阅读
雨天是最美
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有