[英]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;
}
}
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:
您可以看到缺点:
DEMO_MAX = 256
, g++ -Os
will actually emit 258 instantiations of factory<>
; DEMO_MAX = 256
, g++ -Os
DEMO_MAX = 256
实际上会发出258个factory<>
实例化; g++ -O4
will keep 74 of those, inlining the rest[2] g++ -O4
将保留其中的74个,其余的则为内联[2] 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. [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
#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;
}
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.