开发者

How to use boost::array with unknown size as object variable

I'd like to use boost::array as a class member, but I do not know the size at compile time. I thought of something like this, but it doesn't work:

int main() {
    boost::array<int, 4> array = {{1,2,3,4}};
    MyClass obj(array);
}

class MyClass {
    private:
        boost::array<int, std::size_t> array;
    public:
        template<std::size_t N> MyClass(boost::array<int, N> array)
        : array(array) {};
};

The compiler, gcc, says:

开发者_运维百科error: type/value mismatch at argument 2 in template parameter list for
  ‘template<class _Tp, long unsigned int _Nm> struct boost::array’
error:   expected a constant of type ‘long unsigned int’, got ‘size_t’

Which obviously means that one cannot use variable-sized arrays as class members. If so, this would negate all the advantages of boost::array over vectors or standard arrays.

Can you show me what I did wrong?


Boost's array is fixed-size based on the second template parameter, and boost::array<int,4> is a different type from boost::array<int,2>. You cannot have instances of the same class (MyClass in your example) which have different types for their members.

However, std::vectors can have different sizes without being different types:

struct MyClass {
  template<std::size_t N>
  explicit
  MyClass(boost::array<int, N> const& array)
  : data(array.begin(), array.end())
  {}

private:
  std::vector<int> data;
};

int main() {
  boost::array<int, 4> a = {{1,2,3,4}};
  MyClass obj(a);

  boost::array<int, 2> a2 = {{42,3}};
  MyClass obj2(a2);

  // notice obj.data.size() != obj2.data.size()

  return 0;
}

That said, boost::array is still useful (it's even useful in this example code), just not in the exact way you want to use it.


You're missing some basic points. You can have:

  1. A statically allocated array - char arr[10];
  2. A dynamically allocated array - char* arr = new arr[10];

The first one's size is known during compile time (because the size is a constant), hence you can preallocate a memory space for it, the other one isn't, hence you need to allocate memory for it during run-time.

STL/TR1/Boost provides wrappers for both types of arrays. Those are not only wrappers for convieniece, but also for safety (range checking in some situations) and power (iterators). For both cases we have a separate wrapper:

  1. Statically allocated array wrapper boost::array<char,10> arr;
  2. Dynamically allocated array wrapper std::vector<char> arr;

The latter has the benefit of being self resizing, and allowing resizing, in addition to being dynamically allocatable. boost::array on the other hand, mimics a type arr[const] construct.

Hence, you need to decide whether you want the class to have statically allocated memory, or dynamically. The former, only makes sense if the classes storage is either fixed size, or one of a few fixed sizes. The latter makes sense in all other cases.

Statically allocated would use templates

template < size_t N >
class MyClass {
private:
    boost::array< int, N > array;
public:
   MyClass(boost::array< int, N > array) : array(array) {};
};

// ...

boost::array<int, 4> array = {{1,2,3,4}};
MyClass<4> obj(array);

But would create separate code for every size of the class, and they would not be inter-operable (this can be circumvented though).

Dynamically allocated would use vectors

class MyClass {
private:
    std::vector< int > array;
public:
   MyClass(const std::vector< int >& array) : array(array) {};
};

Don't be afraid of vectors, treat them as dynamically allocated arrays -- the resizingness of vectors is an added benefit that doesn't affect performance almost at all.


May I suggest using boost::scoped_array instead? On the other hand, you might not want to actually copy the whole array every time. Then boost::shared_array would be a better choice.


No, boost::array (it's in TR1 as std::tr1::array) is a statically sized buffer. The point of the class is to avoid a dynamic memory allocation - you can put a boost::array entirely on the stack.

You can make your example class take a template int and pass that to the boost::array member,

template<int Size>
class MyClass
{
private:
    boost::array<int, Size> m_array;
public:
    // ....
};

But that is just dressing, it's still a static allocation.


You're wrong about the error :

    template<unsigned long N> MyClass(boost::array<int, N> array) : array(array) {};

Should work. By the way this will still generate the array at compile time so it's not a good solution. And other errors will occur.

Here what you want is a vector, with a reserved size and some assertions that keep the capacity on a fixed size.


Though you already accepted an answer, please note that std::vector may not be the right choice for your task. If you want to create the array once - a fixed size array - and you do not want to resize it later on, then a good old plain array may be the right choice for you! Ignore boost::array, ignore std::vector, its intents are very different, keep it simple. KISS, YAGNI and so on...

int main() {
    int* array = new int[4];
    for( int i=0; i<4; ++i ) array[i] = i+1;
    MyClass obj(array);
}

class MyClass {
    private:
        int* array;
    public:
        MyClass( int* array )
        : array(array) {}
        ~MyClass() { delete[] array; }
};

EDIT: As Nikolai N Fetissov already stated, boost::scoped_array might be a good choice. It provides a thin RAII wrapper around the array. Here is a usage example (hope it is correct, feel free to edit otherwise):

class MyClass {
    private:
        boost::scoped_array<int> array;
    public:
        MyClass( int* array )
        : array(array) {}
};


If you don't need dynamic resizing, you don't need std::vector

just have the function accept *int

MyFunction (int* array,int size); // function prototype

and pass it the boost::array 's .data() pointer to the data...

boost::array<int,4> testArray;
boost::array<int,5> testArray2;

// Calling the function:
MyFunction(testArray.data(),4);
MyFunction(testArray2.data(),5);

the key is .data() people!!! If you want boost arrays to replace regular arrays, this is perhaps the way (without having to use templates and all that)

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜