【问题标题】:How to use boost::array with unknown size as object variable如何使用大小未知的 boost::array 作为对象变量
【发布时间】:2011-01-03 04:01:42
【问题描述】:

我想使用 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 相对于向量或标准数组的所有优势。

你能告诉我我做错了什么吗?

【问题讨论】:

    标签: c++ arrays class boost templates


    【解决方案1】:

    Boost 的数组基于第二个模板参数是固定大小的,boost::array&lt;int,4&gt; 是与boost::array&lt;int,2&gt;不同类型。您不能拥有其成员具有不同类型的同一类(在您的示例中为 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 仍然有用(它甚至在此示例代码中也很有用),只是不是以您想要使用它的确切方式。

    【讨论】:

      【解决方案2】:

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

      1. 一个静态分配的数组 - char arr[10];
      2. 一个动态分配的数组 - char* arr = new arr[10];

      第一个的大小在编译时是已知的(因为大小是一个常量),因此你可以为它预分配一个内存空间,另一个不是,因此你需要分配在运行时为其提供内存。

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

      1. 静态分配的数组包装boost::array&lt;char,10&gt; arr;
      2. 动态分配的数组包装std::vector&lt;char&gt; arr;

      除了可以动态分配之外,后者还具有自我调整大小和允许调整大小的好处。另一方面,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) {};
      };
      

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

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          【解决方案4】:

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

          您可以让您的示例类采用模板 int 并将其传递给 boost::array 成员,

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

          不过那只是装扮,还是静态分配。

          【讨论】:

          • 请注意,此解决方案将问题转移到 MyClass 类(其中每个模板实例化将成为不同的类型)。根据提问者的实际任务,这可能有效,但我对此表示怀疑。
          • 又是“它是”没有配置,这句话有误导性。
          • 这就是我所说的“修饰”的意思,静态大小的分配(和堆栈分配)仍然是分配。
          【解决方案5】:

          你错了:

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

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

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

          【讨论】:

          • 提到的错误是关于boost::array&lt;int, std::size_t&gt;,他似乎解释正确。
          【解决方案6】:

          虽然您已经接受了答案,但请注意 std::vector 可能不是适合您的任务。如果你想创建一次数组 - 一个固定大小的数组 - 并且你不想在以后调整它的大小,那么一个好的旧的普通 array 可能是正确的选择为你!忽略 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) {}
          };
          

          【讨论】:

          • 嗯,这里缺少拷贝构造函数和拷贝赋值运算符。
          • boost::array/tr1::array 是固定大小数组的一个非常薄的包装器——事实上,它的开销为零。当 tr1::array 可用时,实际上没有理由使用 C 样式的数组。
          • 特里:你读过真正的问题吗?如果您不理解提问者的意图,没有理由拒绝我。
          • Terry:当数组的大小在编译时未知时,“C 样式数组”,正如您所说的那样,非常适合。 tr1/boost::array 要求在编译时知道大小,所以这是不可能的。这就是重点。
          【解决方案7】:

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

          只要让函数接受 *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 数组来替换常规数组,这也许是一种方式(不必使用模板等)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-04-21
            • 2012-05-08
            • 2021-11-23
            • 2018-05-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-04-15
            相关资源
            最近更新 更多