我有一个特殊的问题。我想创建包含可变长度数组的类。我不想出于局部性的原因在堆上分配数组(当我这样做时,代码减慢了2倍)。我不想使用虚函数,因为我不想为函数调用付费。以下代码可以工作(在我的编译器/平台上),但需要注意。
include <iostream>
include <boost/array.hpp>
struct Base
{
Base(size_t s):
size(s) {}
int& up(size_t i) { return *(reinterpret_cast<int*>((&size) + 1) + i); }
size_t size;
};
template<size_t sz>
struct Derived: public Base
{
boost::array<int, sz> data;
Derived(): Base(sz) {}
};
int main()
{
Derived<5> d5;
d5.data[2] = 1234;
Base* b = &d5;
std::cout << b->up(2) << std::endl;
}
这令人难以置信的丑陋; reinterpret_cast&lt; ...&gt;是一面红旗。此外,需要注意的是,如果我将size_t
更改为short unsigned
(我猜编译器会填充类),则会失败。
所以问题是:有没有办法使这个便携式?有没有办法从Base
确定第一个成员变量在其派生类中的位置?
答案 0 :(得分:3)
我想到了一个想法:让Derived
构造函数在Base
成员中存储指向其数据的指针。
struct Base
{
protected:
size_t size;
int * array;
Base(size_t s, int * arr):
size(s), array(arr)
{ }
public:
int& up(size_t i) { return array[i]; }
size_t getSize() { return size; }
};
template<size_t sz>
struct Derived: public Base
{
std::array<int, sz> data;
Derived():
Base(sz, &data[0])
{ }
};
int main()
{
Derived<5> d5;
d5.data[2] = 1234;
Base* b = &d5;
std::cout << b->up(2) << std::endl;
}
答案 1 :(得分:2)
从您的评论中,听起来像这样的事情就足够了:
#include <cstddef>
#include <array>
#include <algorithm>
template <typename T>
struct ArrayBase
{
typedef T type;
type & operator[](std::size_t i) { return buf[i]; }
type const & operator[](std::size_t i) const { return buf[i]; }
protected:
ArrayBase(type * p) : buf(p) { }
private:
type * buf;
};
template <typename T, std::size_t N>
struct Array : ArrayBase<T>
{
Array()
: ArrayBase<T>(a.data())
{
}
Array(Array const & rhs)
: ArrayBase<T>(a.data())
{
std::copy(rhs.a.begin(), rhs.a.end(), a.begin());
}
private:
std::array<T, N> a;
};
用法:
Array<int, 5> a5;
ArrayBase<int> & b = a5;
b[2] = 11;
Array<int, 5> a52 = a5;
a52[2] = 13;
答案 2 :(得分:0)
这是一个危险但又快速而小的答案:
template<class T>
struct alloca_magic {
T* b;
int s;
alloca_magic(void* bu, int sz)
: b((T*)(bu)),s(sz)
{new(b)T[s];}
~alloca_magic()
{for(int i=0;i<s;++i)(b+i)->~T();}
operator T*() {return b;}
};
#define alloca_magic(Type,Name,Size) void* t = alloca(sizeof(Type)*Size); alloca_magic<Type> Name(t,Size);
#include <iostream>
struct test {
int data;
test() {std::cout << "ctor\n";}
~test() {std::cout << "dtor\n";}
};
void foo(int len) {
std::cout << "begin foo\n";
alloca_magic(test ,buffer,len);
for(int i=0; i<len; i++)
buffer[i].data = i;
std::cout << "end foo\n";
}
int main() {
int len;
std::cin >> len;
std::cout << "begin main\n";
alloca_magic(test ,buffer,len);
for(int i=0; i<len; i++)
buffer[i].data = i;
foo(len);
std::cout << "end main\n";
}
begin main
ctor
ctor
ctor
begin foo
ctor
ctor
ctor
end foo
dtor
dtor
dtor
end main
dtor
dtor
dtor
对于Windows,您必须将alloca
替换为_alloca
。请记住,这很容易被滥用和破坏,如果大量完成可能会导致堆栈溢出。除了速度测试之外,我不推荐这个,但可能也没有。