简体   繁体   English

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

[英]Array with undefined size as Class-member

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?我怎样才能实现这种行为?

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

Declare it as: 声明为:

int* array;

Then you can initialize it this way: 然后,您可以通过以下方式对其进行初始化:

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

Don't forget to free the memory in the destrutor: 不要忘记释放销毁者的内存:

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

Is the class declaration complete ? 类声明是否完整? If the constructor of the class takes the size of the array as an argument and you don't want to resize the array, then templatizing the class can give you runtime behaviour. 如果类的构造函数将数组的大小作为参数,并且您不想调整数组的大小,则对类进行模板化可以为您提供运行时行为。

Now, we don't have to pass the size of the array as argument to the constructor. 现在,我们不必将数组的大小作为参数传递给构造函数。

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; 

    }
}

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: 好的,受此处 UncleBens挑战的启发,我想出了一个概念验证( 请参见下文 ),让您实际进行:

  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. 它涉及factory<>::instantiate中的模板技巧,该技巧实际上使用编译时元二进制搜索将指定的(运行时)维与一系列明确的static_array类模板实例化进行匹配。

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<> ; DEMO_MAX = 256g++ -Os DEMO_MAX = 256实际上会发出258个factory<>实例化; g++ -O4 will keep 74 of those, inlining the rest[2] g++ -O4将保留其中的74个,其余的则为内联[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; 编译的伸缩性不好:在DEMO_MAX = MAX_RAND编译需要大约2m9的时间...在64位8GB的计算机上耗尽内存; at MAX_RAND>>16 it takes over 25 minutes to possibly compile (?) while nearly running out of memory. MAX_RAND>>16需要在25分钟内可能编译(?),而几乎耗尽内存。 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. 从好的方面来说,该示例演示了此类(0..256)的合理范围,并且在我的64位linux上仅用4秒和800Kb即可进行编译。 See also a down-scaled, ANSI-proof version at codepad.org 另请参见codepad.org上的缩小尺寸,符合ANSI标准的版本

[2] established that with objdump -Ct test | grep instantiate | cut -c62- | sort -k1.10n [2] objdump -Ct test | grep instantiate | cut -c62- | sort -k1.10n 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;
}

I'm working on this too for solving a dynamic array problem - I found the answer provided was sufficient to resolve.我也在努力解决动态数组问题 - 我发现提供的答案足以解决。

This is tricky because arrays in functions from my reading do not continue after function ends, arrays have a lot of strange nuance, however if trying to make a dynamic array without being allowed to use a vector, I believe this is the best approach..这很棘手,因为我阅读的函数中的 arrays 在 function 结束后不会继续,arrays 有很多奇怪的细微差别,但是如果试图在不允许使用向量的情况下创建动态数组,我相信这是最好的方法。

Other approaches such as calling new and delete upon the same pointed to array can/will lead to double free pending the compiler as it causes some undefined behavior.其他方法(例如在同一个指向的数组上调用 new 和 delete)可能/将导致编译器双重释放挂起,因为它会导致某些未定义的行为。

class arrayObject
{
public:
arrayObject();
~arrayObject();
int   createArray(int firstArray[]);
void  getSize();
void  getValue();
void  deleting();
// private: 
int *array;
int size;
int counter;
int number;
};

arrayObject::arrayObject()
{
this->array = new int[size];
}

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

In response to critics in the comments 在评论中回应评论家

I think many people fail to notice a crucial given in the question: since the question asks specifically how to declare an int[N] array inside a struct, it follows that each N will yield a distinct static type to the compiler. 我想,很多人没有注意到这个问题给出了至关重要的:因为这个问题问具体如何申报int[N]一个结构里面阵列,它遵循每个N将产生不同的静态类型的编译器。

As much as my approach is being 'critiqued' for this property, I did not invent it: it is a requirement from the original question. 对于此属性,尽管我的方法受到了“批评”,但我并没有发明它:这是原始问题的要求。 I can join the chorus saying: "just don't" or "impossible" but as a curious engineer I feel I'm often more helped by defining the boundaries of ust what is in fact still possible . 我可以加入合唱,说: “只是不做”“不可能”,但是作为一名好奇的工程师,我觉得定义ust的界限通常会为我提供更多帮助, 而实际上仍然是可能的

I'll take a moment to come up with a sketch of an answer to mainly UncleBen interesting challenge. 我将花点时间提出一个主要针对UncleBen有趣挑战的答案的草图。 Of course I could hand-waive 'just use template metaprogramming ' but it sure would be more convincing and fun to come up with a sample 1 当然,我可以免除“仅使用模板元编程 ”,但是提出一个示例1肯定会更有说服力和乐趣

1 only to follow that sample with a big warning: don't do this in actual life :) 1 只是在警告该示例之后才发出警告:在现实生活中不要这样做 :)


The TR1 (or c++0x) type std::array does exactly that; TR1(或c ++ 0x)类型std :: array正是这样做的; you'll need to make the containing class generic to cater for the array size: 您需要使包含类通用以适应数组大小:

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

You can make the thing easier to work with by doing a smart template overloaded factory: 通过执行智能模板重载工厂,可以使事情更容易使用:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用 std::function 作为类成员创建回调 - Creating a callback with std::function as class-member 如何获取offsetof()私有类成员? - How to get offsetof() a private class-member? 消除多重继承中的类成员歧义 - Disambiguate class-member in multiple inheritance 防止并发读/写类成员 - Preventing concurrent read/write to class-member 初始化具有参数的类成员对象的正确方法 - Correct way to initialize class-member objects that have parameters 如何为多个模板值(常量)专门化一个类成员? - How to specialize a class-member for multiple template values (constants)? 将类成员 function 作为参数传递给全局 function - Passing a class-member function to a global function as argument 为了更多“const”成员函数的目的而指定类成员互斥体“可变”是否“正确”? - Is it "correct" to specify class-member mutex 'mutable' for the purpose of much-more 'const' member functions? 如何实现使用非静态类字段的一系列类成员回调? - How to implement series of class-member callbacks, that use non-static class fields? 将数组传递给类的未声明大小的数组成员 - Pass an array to an array member of undeclared size of a class
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM