2

我有一个可变长度的数据结构,一个多维迭代器:

class Iterator
{
public:
    static Iterator& init(int dim, int* sizes, void* mem)
    {
        return *(new (mem) Iterator(dim, sizes));
    }

    static size_t alloc_size(int dim)
    {
        return sizeof(Iterator) + sizeof(int) * 2 * dim;
    }

    void operator++()
    {
        // increment counters, update pos_ and done_
    }

    bool done() const { return done_; }
    bool pos()  const { return pos_; }

private:
    Iterator(int dim, int* sizes) : dim_(dim), pos_(0), done_(false)
    {
        for (int i=0; i<dim_; ++i) size(i) = sizes[i];
        for (int i=0; i<dim_; ++i) counter(i) = 0;
    }

    int  dim_;
    int  pos_;
    bool done_;
    int  size   (int i) { return reinterpret_cast<int*>(this+1)[i]; }
    int& counter(int i) { return reinterpret_cast<int*>(this+1)[dim_+i]; }
};

迭代器的维度在编译时是未知的,但可能很小,所以我为迭代器分配内存alloca

void* mem = alloca(Iterator::alloc_size(dim));

for (Iterator& i = Iterator::create(dim, sizes, mem); !i.done(); ++i)
{
    // do something with i.pos()
}

有没有更优雅的方式为迭代器分配内存?我知道从函数返回时,它的堆栈被展开,因此alloca必须在调用者的堆栈框架中使用(参见例如here)。这个答案建议在默认参数中执行分配:

static Iterator& init(int dim, int* sizes, void* mem = alloca(alloc_size(dim)));

不管多么优雅,这个解决方案对我没有帮助:Default argument references parameter 'dim'. 有什么好的解决方案建议吗?

4

4 回答 4

2

不幸的是,鉴于这dim是一个运行时值,除了使用宏之外没有其他方法可以做到这一点:

#define CREATE_ITERATOR(dim, sizes) \
    Iterator::init(dim, sizes, alloca(Iterator::alloc_size(dim)))
于 2012-07-20T12:01:17.323 回答
1

您可以将维度参数作为模板参数。

于 2012-07-20T11:15:50.477 回答
0

我的建议可能不是您正在寻找的,但为什么没有一个 create|make_iterator 函数来执行 alloca 调用?

于 2012-07-20T11:50:03.817 回答
0

我根本不建议使用 alloca。如果 dim 值很小,那么类中的一些固定大小的缓冲区就足够了。如果 dim 很大,那么与在迭代器上执行的其他操作的复杂性相比,堆分配成本可以忽略不计(请注意,对于非常大的 dim 值,alloca 可能会导致堆栈溢出)。您可以在运行时在固定缓冲区和堆分配之间进行选择,具体取决于昏暗大小。

所以我会推荐类似于 std::string 中的小字符串优化的方法。

也许,某种 COW(写时复制http://en.wikipedia.org/wiki/Copy-on-write)技术可能对您的迭代器也有用。

请注意,此技术不能与 alloca 一起使用,只能与堆分配一起使用。此外,如果迭代器使用 alloca(至少没有越来越丑陋的宏),则几乎不可能复制或复制初始化迭代器。

Alloca是邪恶的:)

于 2012-07-20T15:05:42.630 回答