如何使用未知大小的boost :: array作为对象变量

时间:2010-01-09 01:27:11

标签: c++ arrays class boost templates

我想使用boost :: array作为类成员,但我不知道编译时的大小。 我想到了类似的东西,但它不起作用:

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) {};
};

编译器gcc说:

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’

这显然意味着不能使用可变大小的数组作为类成员。如果是这样,这将否定boost :: array相对于向量或标准数组的所有优点。

你能告诉我我做错了吗?

7 个答案:

答案 0 :(得分:19)

Boost的数组是基于第二个模板参数的固定大小,而boost::array<int,4>是来自boost::array<int,2>不同类型。您不能拥有同一类的实例(在您的示例中为MyClass),这些实例的成员具有不同的类型。

但是,std :: vectors可以有不同的大小而不是不同的类型:

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;
}

也就是说,boost :: array仍然有用(在这个示例代码中它甚至很有用),只是没有你想要使用它的确切方式。

答案 1 :(得分:12)

你遗漏了一些基本要点。你可以:

  1. 静态分配的数组 - char arr[10];
  2. 动态分配的数组 - char* arr = new arr[10];
  3. 第一个的大小在编译期间是已知的(因为大小是常量),因此你可以为它预先分配一个内存空间,另一个不是,因此你需要分配在运行期间为它记忆。

    STL / TR1 / Boost为两种类型的数组提供包装器。这些不仅包括对手的包装,也包括安全性(在某些情况下进行范围检查)和电源(迭代器)。对于这两种情况,我们都有一个单独的包装器:

    1. 静态分配的数组包装器boost::array<char,10> arr;
    2. 动态分配数组包装器std::vector<char> arr;
    3. 后者具有自我调整大小的优点,除了可动态分配外,还允许调整大小。另一方面,boost::array模仿type arr[const]构造。

      因此,您需要决定是要让类具有静态分配的内存还是动态分配内存。前者只有在类存储是固定大小或几个固定大小之一时才有意义。后者在所有其他情况下都有意义。

      静态分配将使用模板

      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);
      

      但是会为每个类的大小创建单独的代码,并且它们不会互操作(尽管可以绕过它)。

      动态分配将使用向量

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

      不要害怕向量,将它们视为动态分配的数组 - 向量的大小调整是一个额外的好处,几乎不影响性能。

答案 2 :(得分:6)

我建议您使用boost::scoped_array吗?另一方面,您可能不希望每次都复制整个数组。那么boost::shared_array将是更好的选择。

答案 3 :(得分:3)

不,boost :: array(它在TR1中作为std :: tr1 :: array)是一个静态大小的缓冲区。该类的要点是避免动态内存分配 - 你可以将boost :: array完全放在堆栈上。

您可以使您的示例类获取模板int并将其传递给boost :: array成员

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

但这只是穿衣,它仍然是静态分配。

答案 4 :(得分:1)

你错了:

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

应该有效。顺便说一下,这仍然会在编译时生成数组,所以这不是一个好的解决方案。还会发生其他错误。

这里你想要的是一个向量,具有保留的大小和一些断言,使容量保持固定的大小。

答案 5 :(得分:1)

虽然您已经接受了答案,但请注意,std :: vector可能是您的任务的正确选择。如果你想创建一次数组 - 固定大小的数组 - 并且你不想稍后调整它,那么一个好的旧的数组可能是正确的选择为了你!忽略boost :: array,忽略std :: vector,它的意图非常不同,保持简单。 KISS,YAGNI等等......

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; }
};

编辑:正如Nikolai N Fetissov所说,boost :: scoped_array可能是一个不错的选择。它在阵列周围提供了一个薄的RAII包装器。这是一个用法示例(希望它是正确的,随意编辑):

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

答案 6 :(得分:0)

如果您不需要动态调整大小,则不需要std :: vector

只需要函数accept * int

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

并将boost :: array的.data()指针传递给数据......

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

// Calling the function:
MyFunction(testArray.data(),4);
MyFunction(testArray2.data(),5);
关键是.data()人!!!如果你想要使用boost数组替换常规数组,这可能就是这种方式(不必使用模板和所有这些)