【问题标题】:Is there a random access container type that accepts a prefilled & preallocated buffer?是否存在接受预填充和预分配缓冲区的随机访问容器类型?
【发布时间】:2011-07-28 03:36:35
【问题描述】:

我正要自己写点东西,因为我没有找到我要找的东西,但我想在潜入之前我应该​​问问人群。

  • 是否存在允许传入预填充缓冲区的 boost 或 stl 随机访问容器类型?

虚构的(?)容器类型会像这样运行:

  const int blobSize = unpackBlobSize( msg );
  int *     blob     = unpackBlobData( msg );

  SpecialVector<int> mySpecialIntVector( blob, blobSize );

基本上,我正在将旧库与 c 风格的原始指针缓冲区连接,但希望使用 C++ 风格的容器语义而不需要复制步骤。我希望得到的是 std::vector 加上预分配和预填充的缓冲区构造函数,并且减去调整大小。

Libeigen 的 Eigen::Map 具有此类功能,允许执行以下操作:

  int array[9];
  for(int i = 0; i < 9; ++i) 
      array[i] = i;
  stl::cout << Eigen::Map<Eigen::Matrix3i>(array) << stl::endl;

有人知道涵盖这些约束的 boost 或 stl 模板吗?

【问题讨论】:

  • 我对这个库不是很熟悉,但我相信 Boost.Range 可能有一些你可以使用的东西。据我了解,它提供了一些薄包装器,使成对的迭代器看起来像容器
  • @Dennis 这似乎是一个真正的解决方案。检查它。
  • @Dennis,你想把它变成答案还是我应该?
  • 请放心,我实际上还没有深入研究它来给出一个可行的例子。
  • 这是我的意思,我没有看到一个例子。 vector 的 API(如果不是自动调整大小)中缺少什么? “安全(er)C++/STL 方式”只是字眼,抱歉。使用内置数组,您可以愉快地用完向量的边界。 vector 唯一更安全的事情是隐式内存管理,但你放弃了。指针只是一种(内置)迭代器,只要您不自己管理内存,就可以使用它们。 STL 只是一个工具,而不是对付坏东西的护身符:)

标签: c++ boost stl iterator containers


【解决方案1】:

根据 Dennis Zickenfoose 的评论,我查找了 Boost.range 似乎提供了完美的解决方案:

  #include <boost/range.hpp>
  #include <boost/foreach.hpp>
  #include <iostream>

  int main()
  {
    const int blobSize = 100;
    int blob[blobSize];

    for( int i = 0; i < blobSize; ++i )
      blob[i] = i;

    boost::iterator_range<int*> blobPsudoContainer( blob, blob + blobSize );

    BOOST_FOREACH( int & i, blobPsudoContainer )
      i = i + 1;

    std::cout << "Size is:" << blobPsudoContainer.size() << "\n";
    std::cout << "value at 0 is:" << blobPsudoContainer[0] << "\n";
    return 0;
  }

谢谢丹尼斯! :)

【讨论】:

  • 不错。我认为我不会想到将boost::range 用于此特定目的。我一直认为它仅用于表示容器的子集 - 将其应用于 C 数组以将数组转换为 container 只是不会进入我的脑海。
  • 现在我越来越贪心了...我想知道是否可以将它安装为自动转换 std 容器类型,这样我就可以让我所有的模板函数签名都采用 boost.range类型并免费涵盖所有基础:)
  • @Catskul:范围不是类型;它们是概念boost::iterator_range 是一种实现范围概念的类型;它恰好由两个用户提供的迭代器定义。您也可以实现满足范围概念的类型。所有标准容器也恰好满足范围概念。
  • @Nicol,“范围不是类型;它们是概念” 是的,我明白了。如果我不这样做,我们就不会进行这种对话;)如果您希望我更冗长,我想说我认为我可能会生成模板化函数,这些函数可以自动从 std 容器类型实例化 boost 范围所以我没有专门处理 std::container 类型和范围。
  • @Catskul:但是你不能从任何东西实例化范围,因为范围是概念,而概念不能被实例化。此外,Boost.Range 已经包含许多处理范围类型的模板算法。它们还具有延迟评估功能,因此您可以有效地将多个算法组合成一个。并且标准容器已经符合范围条件,因此任何接受范围概念的模板函数都将接受标准容器。
【解决方案2】:

没有你想要的,这只是语言的一个缺点。如果您对让分配器静态猜测一个好的预期最大元素数感到满意,您可以在分配器中嵌入一个普通的 C 数组并尽可能长时间地遵循它;这通常称为自动缓冲区。


旧答案:

所有标准库容器都允许您指定分配器。你可以做一个缓冲区分配器。

【讨论】:

  • 非常有趣的想法。不过,我仍然会遇到调整大小的问题。
  • @Catskul 调整大小时它将使用您的自定义分配器。
  • 看起来他希望提供的缓冲区已经包含初始化值;标准库容器将假定分配器返回未初始化的内存,并覆盖现有数据。
  • 我正要写它,但现在我们应该澄清一下:@Cat:你想传入缓冲区,还是假设某种预期的静态缓冲区。为什么还要动态分配缓冲区?
  • @Catskul:那么也许我错过了一些东西,但为什么不开始使用你的缓冲区呢?将其粘贴在 std::vector&lt;&gt; 中然后不使用 std::vector 功能有什么好处?
【解决方案3】:

我想我会发布我最终使用的自定义解决方案,以防万一有人好奇或有任何 cmets。请原谅严格的格式;这是为了摆脱水平滚动。

如果您使用它,请在评论部分告诉我。我很想知道它是否对其他人有用。

我们需要以下标题:

 #include <boost/range/iterator_range.hpp>
 #include <boost/shared_ptr.hpp>
 #include <boost/shared_array.hpp>
 #include <vector>

挂钩到现有的引用对象的助手

 template<typename RefCountedTypeT>
 struct RefCountLinkFunctor
 {
   public:
     RefCountLinkFunctor( const RefCountedTypeT & ptr ) 
       : m_ptr(ptr) 
     { 
       &RefCountedTypeT::use_count; // try to check if refcounted
      } 

      template<typename T> void operator()(T*) {}

   protected:
     RefCountedTypeT m_ptr;
 };

然后:

 template< typename DataT >
 class DataRange : public boost::iterator_range< DataT * >
 {
 public:
   typedef boost::iterator_range< DataT * >    ParentType;
   typedef DataRange< DataT >                  OwnType;
   typedef DataT                               DataType;
   typedef boost::iterator_range< DataType * > Range;
   typedef boost::shared_ptr< OwnType >        Ptr;
   typedef std::vector<DataType>               DataVector;
   typedef boost::shared_ptr<DataVector>       DataVectorPtr;

   static Ptr allocateShared( std::size_t size )
   {
     typedef boost::shared_array<DataType>         DataSharedArray;
     typedef RefCountLinkFunctor<DataSharedArray>  Deleter;

     DataSharedArray   dataArray( new DataType[size] );
     Deleter           deleter( dataArray );

     DataT * begin = dataArray.get();
     DataT * end   = begin + size;

     return Ptr( new OwnType(begin, end), deleter);
   }

   template< typename RefCountedT >
   static Ptr 
   makeShared( DataType * begin, DataType * end, const RefCountedT & refObj )
   {
     RefCountLinkFunctor< RefCountedT >  deleter( refObj );
     return Ptr( new OwnType(begin, end), deleter );
   }

   template< typename RefCountedT, typename InDataT >
   static Ptr 
   makeShared( DataVector & data, const RefCountedT & refObj )
   {
     RefCountLinkFunctor< RefCountedT >  deleter( refObj );

     DataType * begin = &data.front();
     DataType * end   = begin + data.size();

     return makeShared( begin, end, deleter );
   }

   static Ptr makeShared( const DataVectorPtr & data )
   {
     typedef boost::shared_ptr< std::vector<DataType> > InputVectorPtr;

     RefCountLinkFunctor< InputVectorPtr >  deleter( data );

     DataType * begin = &data->front();
     DataType * end   = begin + data->size();

     return makeShared( begin, end, deleter );
   }

 protected:
     DataRange( DataType * begin, DataType * end ) : ParentType( begin, end ){}

};

【讨论】:

    猜你喜欢
    • 2013-10-28
    • 2019-07-31
    • 2011-08-04
    • 2013-09-26
    • 2019-09-22
    • 2021-10-26
    • 1970-01-01
    • 2014-04-10
    • 1970-01-01
    相关资源
    最近更新 更多