C ++中兼容的可变长度结构 [英] compliant variable length struct in C++

查看:93
本文介绍了C ++中兼容的可变长度结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在标准C语言中,您可以使用大小为0的数组结束结构,然后对其进行过度分配以向该数组添加可变长度的维度:

In standard C you can end a struct with an array of size 0 and then over allocate it to add a variable length dimension to the array:

struct var
{
    int a;
    int b[];
}

struct var * x=malloc(sizeof(var+27*sizeof(int)));

如何在C ++中以标准(便携式)方式做到这一点?
可以限制最大可能的大小,而且显然不必在堆栈上工作

How can you do that in C++ in a standard (portable) way? It is okay to have a constraint of max posible size and obviously doesn't have to work on the stack

我在想:

class var
{
...
private:
  int a;
  int b[MAX];
};

,然后使用分配器或根据需要的大小重载new / delete以分配不足:

and then use allocators or overload new/delete to under allocate based on the required size:

(sizeof(var)-(MAX-27)* sizeof(int)

(sizeof(var) - (MAX-27)*sizeof(int)

但是,尽管它似乎可以工作,这不是我想要维护的东西。

But, while it seems to work, its not something I'd want to have to maintain.

是否有一种更清洁的方式完全是标准/便携式的?

Is there a cleaner way that is fully standard/portable?

推荐答案

简单地使用C语言的变体有什么问题?

What's wrong with simply doing a variant of the C way?

如果结构必须保持纯POD

If the structure has to remain purely POD, the C way is fine.

struct var
{
    int a;
    int b[1];

    static std::shared_ptr<var> make_var(int num_b) {
        const extra_bytes = (num_b ? num_b-1 : 0)*sizeof(int);
        return std::shared_ptr<var>(
                new char[sizeof(var)+extra_bytes ],
                [](var* p){delete[]((char*)(p));});
}

由于它是POD,所以一切都像d

since it's a POD, everything works just like it did in C.

如果不能保证 b POD,然后事情变得更加有趣。我没有测试过任何东西,但看起来或多或少都像这样。请注意, make_var 依赖 make_unique ,因为它使用了lambda析构函数。您可以在不使用此功能的情况下使其正常运行,但这需要更多代码。就像C方式一样,除了它干净地用构造函数和析构函数处理可变数量的类型,并处理异常

If b is not guaranteed to be POD, then things get more interesting. I haven't tested any of it, but it would look more or less like so. Note that make_var relies on make_unique, because it uses a lambda destructor. You can make it work without this, but it's more code. This works just like the C way, except it cleanly handles variable amounts of types with constructors and destructors, and handles exceptions

template<class T>
struct var {
    int a;

    T& get_b(int index) {return *ptr(index);}
    const T& get_b(int index) const {return *ptr(index);}

    static std::shared_ptr<var> make_var(int num_b);
private:
    T* ptr(int index) {return static_cast<T*>(static_cast<void*>(&b))+i;}
    var(int l);
    ~var();
    var(const var&) = delete;
    var& operator=(const var&) = delete;

    typedef typename std::aligned_storage<sizeof(T), std::alignof(T)>::type buffer_type;
    int len;
    buffer_type b[1];
};
template<class T> var::var(int l)
    :len(0)
{
    try {
        for (len=0; len<l; ++len)
            new(ptr(i))T();
    }catch(...) {
        for (--len ; len>=0; --len)
            ptr(i)->~T();
        throw;
    }
}
template<class T> var::~var()
{
    for ( ; len>=0; --len)
        ptr(i)->~T();
}
template<class T> std::shared_ptr<var> var::make_var(int num_b)
{
    const extra_bytes = (num_b ? num_b-1 : 0)*sizeof(int);
    auto buffer = std::make_unique(new char[sizeof(var)+extra_bytes ]);
    auto ptr = std::make_unique(new(&*buffer)var(num_b), [](var*p){p->~var();});
    std::shared_ptr<var> r(ptr.get(), [](var* p){p->~var(); delete[]((char*)(p));});
    ptr.release();
    buffer.release;
    return std::move(r);
}

由于未经测试,它甚至可能无法编译,并且可能错误。我通常会使用 std :: unique_ptr ,但是我懒得做适当的独立删除器,而 unique_ptr 是当删除程序是lambda时,很难从函数返回。如果您想使用这样的代码,请使用适当的独立删除器。

Since this is untested, it probably doesn't even compile, and probably has bugs. I'd normally use std::unique_ptr but I'm too lazy to make proper standalone deleters, and unique_ptr is hard to return from a function when the deleter is a lambda. On the off chance you want to use code like this, use a proper standalone deleter.

这篇关于C ++中兼容的可变长度结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆