开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜