未定义大小的数组作为类成员

时间:2011-08-20 22:22:30

标签: c++ arrays

我正在寻找一种方法来将数组定义为具有未定义大小的类成员(将在初始化时定义)。

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;
}

我该如何实现这种行为?

5 个答案:

答案 0 :(得分:6)

为什么不使用std::vector<int>

答案 1 :(得分:1)

声明为:

int* array;

然后你可以这样初始化它:

MyArrayOfInts::MyArrayOfInts(int length) {
    this->array = new int[length];
}

不要忘记释放破坏者的记忆:

MyArrayOfInts::~MyArrayOfInts() {
    delete [] this->array;
}

答案 2 :(得分:1)

班级声明是否完整?如果类的构造函数将数组的大小作为参数,并且您不想调整数组的大小,那么对类进行模板化可以为您提供运行时行为。

现在,我们不必将数组的大小作为参数传递给构造函数。

template<size_t size>
class MyClass
{
public:

    MyClass()  { std::iota(arr_m, arr_m + size, 1);  }
    int operator[](int index) const
    {
        return arr_m[index];
    }
    int& operator[](int index)
    {
        return arr_m[index];
    }

    void Set(size_t index, int value)
    {
        arr_m[index] = value;
    }

private:
    int arr_m[size];
};

int main()
{
    {
        MyClass<5> obj;
        std::cout << obj[4] << std::endl;
    }
    {
        MyClass<4> obj;
        std::cout << obj[3] << std::endl; 
        obj.Set(3, 30);
        std::cout << obj[3] << std::endl; 

    }
}

答案 3 :(得分:1)

概念证明

好的,受到UncleBens挑战here的启发,我提出了一个概念证明(见下文),让你真正做到了:

  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);
  }

它围绕factory<>::instantiate中的模板技巧,它实际上使用编译时元二进制搜索来将指定的(运行时)维度与一系列显式static_array类模板实例化相匹配。

我觉得需要重复一遍,这不是好的设计,我只提供代码示例,以显示可以做什么的限制 - 合理的effor,以实现问题的实际目标。你可以看到缺点:

  • 编译器被大量无用的静态类型瘫痪,并创建了如此庞大的类,以至于它们成为性能责任或可靠性危险(堆栈分配任何人? - &gt;我们正在'堆栈溢出' 已经:))
  • DEMO_MAX = 256g++ -Os实际上会发出258个factory<>实例; g++ -O4将保留其中的74个,其余内容[2]
  • 编译不能很好地扩展:在DEMO_MAX = MAX_RAND编译需要大约2m9s才能...在64位8GB机器上耗尽内存;在MAX_RAND>>16可能编译(?)需要超过25分钟,而内存几乎耗尽。它真的需要一些丑陋的手动优化才能消除这些限制 - 如果你能原谅我的话,我真的没那么疯狂,如果你能原谅我的话。
  • 在好的方面,这个示例演示了这个类(0..256)可以理解的合理范围,并且在我的64位linux上仅用了4秒和800Kb进行编译。另请参阅 down-scaled, ANSI-proof version at codepad.org

[2] objdump -Ct test | grep instantiate | cut -c62- | sort -k1.10n

建立了联系

告诉我 CODE 已经!

#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;
}

答案 4 :(得分:0)

回应评论中的批评者

我认为很多人都没有注意到问题中的一个重要内容:因为问题具体如何在结构中声明 int[N] 数组, 遵循,每个 N 将为编译器提供不同的静态类型。

尽管我的方法被“批判”了这个属性,但我没有发明它:这是原始问题的要求。我可以加入合唱团的说法:“只是不要”“不可能”但作为一个好奇的工程师我觉得我通常会通过定义ust的界限来帮助我实际上仍然是可能的

我会花点时间想出一个主要是UncleBen有趣挑战的答案草图。当然,我可以放弃“只使用template metaprogramming”,但肯定会更有说服力,有趣来提出样本1

1 只是为了跟踪该示例并发出重大警告:在实际生活中不要执行 :)


TR1(或c ++ 0x)类型std :: array正是这样做的;你需要使包含类通用以满足数组大小:

template <size_t N> struct MyArrayOfInts : MyArrayOfIntsBase /* for polymorphism */
{
    std::array<int, N> _data;

    explicit MyArrayOfInts(const int data[N])
    {
        std::copy(data, data+N, _data);
    }
};

通过智能模板重载工厂,您可以更轻松地使用它:

template <size_t N>
    MyArrayOfInts<N> MakeMyArray(const int (&data)[N])
    { return MyArrayOfInts<N>(data); }