我正在寻找一种方法来将数组定义为具有未定义大小的类成员(将在初始化时定义)。
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;
}
我该如何实现这种行为?
答案 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,以实现问题的实际目标。你可以看到缺点:
DEMO_MAX = 256
,g++ -Os
实际上会发出258个factory<>
实例; g++ -O4
将保留其中的74个,其余内容[2] DEMO_MAX = MAX_RAND
编译需要大约2m9s才能...在64位8GB机器上耗尽内存;在MAX_RAND>>16
,可能编译(?)需要超过25分钟,而内存几乎耗尽。它真的需要一些丑陋的手动优化才能消除这些限制 - 如果你能原谅我的话,我真的没那么疯狂,如果你能原谅我的话。 [2] 与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;
}
答案 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); }