Using new with fixed length array typedef
How do I define a typedef for a fixed length array so that I can also 'new'. The following do开发者_运维技巧es not work:
typedef double Vector[3];
Vector *v = new Vector; // does not compile
We are trying to wrap into C++ some old C code which handles float *
and float (*)[3]
in a generic way.
The pointer to an double[3]
is double *
- so this will work:
typedef double Vector[3];
double *v = new Vector;
But I suggest you don't use it that way - to delete the array you need the array-delete-operator:
delete[] v;
But on new Vector
you don't see it is an array and so it might be forgotten.
This case is handled (and strongly recommended to avoid) in Scott Meyers Effective C++. So better don't use an typedef here.
class Vector
{
public: // methods
double * data() { return mData; }
const double * data() const { return mData; }
double & operator[](int i) { return mData[i]; }
double operator[](int i) const { return mData[i]; }
private: // attributes
double mData[3];
};
will allow
Vector * pv = new Vector;
Vector & v = *pv;
v[0] = 1;
v[1] = 2;
v[2] = 3;
pass_it_to_legacy_lib(v.data());
delete pv;
One issue with your original example is that it would invoke the new
operator where the new[]
would actually be correct. Also, it would make it non-obvious that delete[]
had to be used instead of plain delete
.
The class approach doesn't need new[]
and takes full advantage of the apriori fixed length.
If you're happy to use templates in your C++ code, something like this could work..
template <typename T, int S>
struct array
{
array() : _inst() {}
template<typename _F>
void operator()(_F & f)
{
f(_inst);
}
operator T*() { return _inst; }
// real array
T _inst[S];
};
typedef array<double, 4> d4;
void foo(double*)
{
}
int main(void)
{
d4 d; // no need for new, but you can use if you want
// first way to call is to pass the function to the array object, which will then
// visit
d(foo);
// take advantage of the type operator (operator T*)
foo(d);
}
#include <cassert>
#include <vector>
using namespace std;
template<typename Type, int Dimension>
const vector<Type> make_fixed_vector(const Type& value = Type())
{
return vector<Type>(Dimension, value);
}
int main(void)
{
vector<int> v3 = make_fixed_vector<int, 3>();
assert(v3.size() == 3);
}
C++1x compilers are able to deduce the type of a variable, which is handy when declaring multi-dimensional "fixed" vectors using this technique:
.
.
.
template<typename Type, int Rows, int Columns>
const vector<vector<Type> > make_fixed_vector_vector(const Type& value = Type())
{
return vector<vector<Type> >(Rows, make_fixed_vector<Type, Columns>(value));
}
int main(void)
{
auto vv = make_fixed_vector_vector<int, 3, 4>(42);
assert(vv.size() == 3);
assert(vv[0].size() == 4);
assert(vv[0][0] == 42);
assert(vv[2][3] == 42);
}
I had this simple idea when programming a parser-function for list expressions which shall return a fixed-size vector of vector of integers. For example, a vector<vector<int> >(1)
for a expression like "(0,8)", but a vector<vector<int> >(2)
for a expression like "(3-4)(5)" and so on. In the application up to 5 parenthesized definitions are possible, which represent logical references to program data. I first try to parse a vector<vector<int> >(5)
. Worked? Ok, got reference type A, the most detailed one. Otherwise vector<vector<int> >(4)
indicates a reference type B etc.
For this purpose make_fixed_vector
worked well, but from a general perspective the technique has flaws. Most notably, since make_fixed_vector
returns no true type, its dimension(s) cannot be checked at compile-time. At runtime reserve
, resize
and push_back
calls are possible. And, since function templates cannot have default template arguments, custom allocators require more typing:
template<typename Type, int Dimension, template<typename> class Allocator>
const vector<Type Allocator<Type> > make_fixed_vector(const Type& value = Type())
{
return vector<Type, Allocator<Type> >(Dimension, value);
}
vector<int> v3 = make_fixed_vector<int, 3, std::allocator>();
etc. etc. But this technique keeps smaller projects basic. Unless this virtue is relevant Boost's boost::array
might be more realistic.
精彩评论