【发布时间】:2012-07-19 15:50:24
【问题描述】:
我有一个可变长度的数据结构,一个多维迭代器:
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)。这个answer 建议在默认参数中执行分配:
static Iterator& init(int dim, int* sizes, void* mem = alloca(alloc_size(dim)));
无论多么优雅,这个解决方案对我没有帮助:Default argument references parameter 'dim'。有什么好的解决方案建议吗?
【问题讨论】:
-
看到这个我眼睛都疼了。看起来像是无限递归 (
bool done() const { return done(); }) 与未定义行为的混合。 -
@TadeuszKopec:呵呵,对,对不起:)我的意思当然是
done_。更正它。 -
我仍然认为
reinterpret_cast的取消引用结果是未定义的行为。为什么是可变大小的对象?好老的std::vector会员有什么问题? -
除了取消引用之外,您还会对
reinterpret_cast的结果做什么?我不是语言律师,所以它可能是未定义的行为,但我想不出这种转换可能会失败的任何情况。还有关于我不使用std::vector的原因:称之为过早优化:) -
您唯一可以对
reinterpret_cast结果做的事情是将其转换回原始类型,前提是中间类型足够大以容纳转换后的值。任何其他用途都是UB。this + 1也是 UB,除非在数组内的对象中使用。