阵列未定义大小类成员 [英] Array with undefined size as Class-member
问题描述
我在寻找一种方法来定义数组作为类成员使用未定义的大小(这将在初始化定义)。
类MyArrayOfInts {
私人的:
INT []数组; //应当用(但)未定义长度声明数组 上市:
MyArrayOfInts(INT);
INT获取(INT);
无效集(INT,INT);
};
MyArrayOfInts :: MyArrayOfInts(INT长度){
这 - >数组= INT [长度] //这里定义的数组
}
INT MyArrayOfInts ::获取(INT指数){
返回这个 - >数组[索引]
}
无效MyArrayOfInts:集(INT指数,int值){
这 - >数组[索引] =值;
}
我怎样才能实现这一行为?
证明概念
好吧,灵感来自UncleBens挑战<一个href=\"http://stackoverflow.com/questions/7135093/array-with-undefined-size-as-class-member/7135200#7135200\">here,我想出了一个验证的概念(见下文的),它可以让你真正做到:
函数srand(123);
的for(int i = 0;我小于10;我++)
{
为size_t N =兰特()%DEMO_MAX; //上限进行演示
性病:: auto_ptr的&LT; iarray&GT;达因(make_dynamic_array(N)); 运动(* DYN);
}
块引用>它围绕着一个模板把戏
工厂&LT;&GT; ::实例化
实际使用编译时元二进制搜索匹配指定(运行时)尺寸一系列明确的static_array
类模板实例。我觉得有必要再重复,这不是好的设计,我公司提供的code样品只显示哪些限制是可以做些什么 - 合理避免费劲,实现问题的实际目标。你可以看到缺点:
- 编译器是残缺的无用静类型的船载货量,并创建一个都这么大了,他们会成为性能责任或可靠性危险(堆栈分配类的人? - >我们上的堆栈溢出的已经:))
- 在
DEMO_MAX = 256
,G ++ -Os
将实际发出工厂&LT 258实例;&GT;
;G ++ -O4
将让那些74,内联,其余[2]- 编译不能很好地扩展:在
DEMO_MAX = MAX_RAND
编译大约需要2m9s到...用完的64位机器8GB内存;在MAX_RAND&GT;&GT; 16
它需要在25分钟内的可能的编译几乎同时运行内存(?)。这将真正需要的丑陋手工优化一些款项以消除这些限制 - 我还没有如此疯狂,以真正做到这一点的工作,如果你不介意的话- 在上涨,这个示例演示可以说是理智的范围内对此类(0..256)和只有4秒,800KB编译在我的64位Linux。也看到了 缩小的,ANSI型版本为codepad.org
[2] 建立与
objdump的-CT测试| grep的实例化|切-c62- |排序-k1.10n
显示我的 code 的了!
的#include&LT;&iostream的GT;
#包括LT&;内存和GT;
#包括LT&;&算法GT;
#包括LT&;&迭代器GT;
#包括LT&;&stdexcept GT;结构iarray
{
的typedef INT VALUE_TYPE;
typedef的VALUE_TYPE *迭代器;
typedef的VALUE_TYPE常量*常量性;
typedef的VALUE_TYPE&安培;参考;
typedef的VALUE_TYPE常量和放大器;为const_reference; 虚拟为size_t大小()常量= 0; 虚拟迭代开始()= 0;
虚拟为const_iterator开始()const的= 0; //完全未经优化的管道只是为了演示purps这里
内嵌迭代结束(){返回开始()+尺寸(); }
内联为const_iterator结束()const的{返回开始()+尺寸(); }
//边界检查是'免费'在这里......为索引的编译时间常数的值
内嵌运营商为const_reference [](为size_t指数)const的{返回*(开始()+指数); }
行内引用操作符[](为size_t指数){返回*(开始()+指数); }
//
虚拟〜iarray(){}
};模板&LT;为size_t N'GT;结构static_array:iarray
{
静态常量为size_t _size = N;
VALUE_TYPE数据[N]; 虚拟为size_t大小()const的{返回_size; }
虚拟迭代开始(){返回数据; }
虚拟为const_iterator开始()const的{返回数据; }
};#定义DEMO_MAX 256模板&LT;为size_t PIVOT = DEMO_MAX / 2,为size_t MIN = 0,为size_t MAX = DEMO_MAX&GT;
结构厂
/ *这确实在一系列静态类型的二进制搜索
*
*由于二进制搜索,这将需要最多2log(MAX)的水平
*递归。
*
*如果参数(为size_t n)是一个编译时间常数前pression,
*具有自动内联在一起,编译器将能够优化
*这一切的方式来简单地返回
*
*新static_array&LT; N&GT;()
*
* TODO静态断言分钟&lt; =&PIVOT LT = MAX
* /
{
联static iarray *实例化(为size_t N)
{
如果(N&GT; MAX || N'LT; MIN)
抛出std :: range_error(不支持大小);
如果(N == PIVOT)
返回新static_array&LT;&PIVOT GT;();
如果(N&GT; PIVOT)
返回工厂≤(PIVOT +(MAX-PIVOT + 1)/ 2),PIVOT + 1,MAX&GT; ::实例化(正);
其他
返回工厂≤(PIVOT - (PIVOT-MIN + 1)/ 2),MIN PIVOT-1。&GT; ::实例化(正);
}
};iarray * make_dynamic_array(为size_t N)
{
返回工厂&LT;&GT; ::实例化(N);
}无效运动(iarray&安培; ARR)
{
INT根= 0;
对于(iarray:迭代它= arr.begin(!);它= arr.end(); ++吧)
*它=(根+ = arr.size()); 性病::法院LT&;&LT; 大小&LT;&LT; arr.size()&所述;&下; :\\ t的;
性病::复制(arr.begin(),arr.end()的std :: ostream_iterator&LT; INT&GT;(STD ::法院));
性病::法院LT&;&LT;的std :: ENDL;
}诠释的main()
{
{//无聊,老派的方法
static_array&所述; 5个I5;
static_array&所述; 17&GT; I17; 运动(I5);
运动(I17);
}
{//兴奋,新奇的,无用的方法
对于(INT N = 0; N&LT; = DEMO_MAX ++ N)
{
性病:: auto_ptr的&LT; iarray&GT;达因(make_dynamic_array(正));
运动(* DYN);
} 尝试{make_dynamic_array(-1); }赶上(的std :: range_error五){性病::法院LT&;&LT; 范围错误OK&LT;&LT;的std :: ENDL; }
尝试{make_dynamic_array(DEMO_MAX + 1); }赶上(的std :: range_error五){性病::法院LT&;&LT; 范围错误OK&LT;&LT;的std :: ENDL; } 返回0; 函数srand(123);
的for(int i = 0;我小于10;我++)
{
为size_t N =兰特()%DEMO_MAX; //上限进行演示
性病:: auto_ptr的&LT; iarray&GT;达因(make_dynamic_array(N)); 运动(* DYN);
}
} 返回0;
}I'm searching for a way to define an array as a class-member with an undefined size (which will be defined on initialization).
class MyArrayOfInts { private: int[] array; // should declare the array with an (yet) undefined length public: MyArrayOfInts(int); int Get(int); void Set(int, int); }; MyArrayOfInts::MyArrayOfInts(int length) { this->array = int[length]; // defines the array here } int MyArrayOfInts::Get(int index) { return this->array[index]; } void MyArrayOfInts:Set(int index, int value) { this->array[index] = value; }
How can I achieve this behaviour ?
解决方案Proof Of Concept
Ok, inspired by UncleBens challenge here, I came up with a Proof-Of-Concept (see below) that let's you actually do:
srand(123); for (int i=0; i<10; i++) { size_t N = rand() % DEMO_MAX; // capped for demo purposes std::auto_ptr<iarray> dyn(make_dynamic_array(N)); exercise(*dyn); }
It revolves around a template trick in
factory<>::instantiate
that actually uses a compile-time meta-binary-search to match the specified (runtime) dimension to a range of explicitstatic_array
class template instantiations.I feel the need to repeat that this is not good design, I provide the code sample only to show what the limits are of what can be done - with reasonable effor, to achieve the actual goal of the question. You can see the drawbacks:
- the compiler is crippled with a boatload of useless statical types and create classes that are so big that they become a performance liability or a reliability hazard (stack allocation anyone? -> we're on 'stack overflow' already :))
- at
DEMO_MAX = 256
,g++ -Os
will actually emit 258 instantiations offactory<>
;g++ -O4
will keep 74 of those, inlining the rest[2]- compilation doesn't scale well: at
DEMO_MAX = MAX_RAND
compilation takes about 2m9s to... run out of memory on a 64-bit 8GB machine; atMAX_RAND>>16
it takes over 25 minutes to possibly compile (?) while nearly running out of memory. It would really require some amounts of ugly manual optimization to remove these limits - I haven't gone so insane as to actually do that work, if you'll excuse me.- on the upside, this sample demonstrates the arguably sane range for this class (0..256) and compiles in only 4 seconds and 800Kb on my 64-bit linux. See also a down-scaled, ANSI-proof version at codepad.org
[2] established that with
objdump -Ct test | grep instantiate | cut -c62- | sort -k1.10n
Show me the CODE already!
#include <iostream> #include <memory> #include <algorithm> #include <iterator> #include <stdexcept> struct iarray { typedef int value_type; typedef value_type* iterator; typedef value_type const* const_iterator; typedef value_type& reference; typedef value_type const& const_reference; virtual size_t size() const = 0; virtual iterator begin() = 0; virtual const_iterator begin() const = 0; // completely unoptimized plumbing just for demonstration purps here inline iterator end() { return begin()+size(); } inline const_iterator end() const { return begin()+size(); } // boundary checking would be 'gratis' here... for compile-time constant values of 'index' inline const_reference operator[](size_t index) const { return *(begin()+index); } inline reference operator[](size_t index) { return *(begin()+index); } // virtual ~iarray() {} }; template <size_t N> struct static_array : iarray { static const size_t _size = N; value_type data[N]; virtual size_t size() const { return _size; } virtual iterator begin() { return data; } virtual const_iterator begin() const { return data; } }; #define DEMO_MAX 256 template <size_t PIVOT=DEMO_MAX/2, size_t MIN=0, size_t MAX=DEMO_MAX> struct factory /* this does a binary search in a range of static types * * due to the binary search, this will require at most 2log(MAX) levels of * recursions. * * If the parameter (size_t n) is a compile time constant expression, * together with automatic inlining, the compiler will be able to optimize * this all the way to simply returning * * new static_array<n>() * * TODO static assert MIN<=PIVOT<=MAX */ { inline static iarray* instantiate(size_t n) { if (n>MAX || n<MIN) throw std::range_error("unsupported size"); if (n==PIVOT) return new static_array<PIVOT>(); if (n>PIVOT) return factory<(PIVOT + (MAX-PIVOT+1)/2), PIVOT+1, MAX>::instantiate(n); else return factory<(PIVOT - (PIVOT-MIN+1)/2), MIN, PIVOT-1>::instantiate(n); } }; iarray* make_dynamic_array(size_t n) { return factory<>::instantiate(n); } void exercise(iarray& arr) { int gen = 0; for (iarray::iterator it=arr.begin(); it!=arr.end(); ++it) *it = (gen+=arr.size()); std::cout << "size " << arr.size() << ":\t"; std::copy(arr.begin(), arr.end(), std::ostream_iterator<int>(std::cout, ",")); std::cout << std::endl; } int main() { { // boring, oldfashioned method static_array<5> i5; static_array<17> i17; exercise(i5); exercise(i17); } { // exciting, newfangled, useless method for (int n=0; n<=DEMO_MAX; ++n) { std::auto_ptr<iarray> dyn(make_dynamic_array(n)); exercise(*dyn); } try { make_dynamic_array(-1); } catch (std::range_error e) { std::cout << "range error OK" << std::endl; } try { make_dynamic_array(DEMO_MAX + 1); } catch (std::range_error e) { std::cout << "range error OK" << std::endl; } return 0; srand(123); for (int i=0; i<10; i++) { size_t N = rand() % DEMO_MAX; // capped for demo purposes std::auto_ptr<iarray> dyn(make_dynamic_array(N)); exercise(*dyn); } } return 0; }
这篇关于阵列未定义大小类成员的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!