阵列未定义大小类成员 [英] Array with undefined size as Class-member

查看:103
本文介绍了阵列未定义大小类成员的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在寻找一种方法来定义数组作为类成员使用未定义的大小(这将在初始化定义)。

 类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 explicit static_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 of factory<>; 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; at MAX_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屋!

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