std :: vector的自包含,STL兼容的实现

时间:2012-02-23 08:40:39

标签: c++ stl vector alignment

Visual Studio 2010和早期版本附带的std::vector的实现具有众所周知的特殊性:resize方法具有以下签名(符合C ++ 03):

void resize(size_type new_size, value_type value);

而不是C ++ 11之前很久以来大多数其他STL实现(如gcc的STL或STLport)使用的符合C ++ 11的签名:

void resize(size_type new_size, const value_type& value);

第一个变体的问题在于,在某些情况下,如果value_type具有对齐规范,则无法编译:

struct __declspec(align(64)) S { ... };
std::vector<S> v;  // error C2719: '_Val': formal parameter with __declspec(align('64')) won't be aligned

这是一个well known问题,除了使用std::vector的不同实现外,没有令人满意的解决方法。

我正在寻找一个写得很好,经过良好测试,自包含和STL兼容的std::vector实施,并且有麻省理工学院风格的许可证,我可以放入我的project作为对齐类型的首选容器。

我考虑过从STLport或gcc的STL中提取它,但是,由于完全符合标准,它们都很大,并且具有许多非平凡的依赖性。

(对于只支持std::vectorpush_backclearcapacity的{​​{1}}合理子集的实现,我会非常满意, sizereserveresize和数组索引。)

有什么想法吗?

2 个答案:

答案 0 :(得分:8)

Eigen库后面的人似乎找到了一个很好的解决方法来解决存储&#34;过度排列的类型&#34; (as Stephan T. Lavavej call them)到Visual Studio的STL中实现的std::vector

它们的实现似乎不必要复杂(检查源herehere),但主要思想是使用瘦包装器封装进入std::vector的类型:

#include <vector>

template <typename T>
struct wrapper : public T
{
    wrapper() {}
    wrapper(const T& rhs) : T(rhs) {}
};

struct __declspec(align(64)) S
{
    float x, y, z, w;
};

int main()
{
    std::vector< wrapper<S> > v;  // OK, no C2719 error
    return 0;
}

关于Eigen的实施,我必须承认我不太了解

  • 为什么他们需要Eigen::aligned_allocator_indirection
  • 为什么他们需要在EIGEN_WORKAROUND_MSVC_STL_SUPPORT
  • 中对算术类型进行例外处理
  • 为什么他们需要在Eigen::workaround_msvc_stl_support
  • 中定义所有这些构造函数和运算符
  • 或者为什么他们需要为resize分配器std::vector部分专业化重新定义Eigen::aligned_allocator_indirection ...

线索欢迎。关键是,这个技巧完美无缺(据我所知)并且我没有看到任何错误,除了可能有点不合时宜。

答案 1 :(得分:1)

最简单(也是最好的,imho)选项是提供一个自由函数作为vector接口的扩展,它做了正确的事情。您需要实现resize的所有功能都可以从std::vector的公共界面获得:

#include <vector>

template<class T, class Alloc>
void resize(std::vector<T, Alloc>& v,
    typename std::vector<T, Alloc>::size_type new_size, T const& val)
{
  if (v.size() < new_size)
      v.insert(v.end(), new_size - v.size(), val);
  else if (new_size < v.size())
      v.erase(v.begin() + new_size, v.end());
}

为了保持一致,单个参数版本:

template<class T, class Alloc>
void resize(std::vector<T, Alloc>& v,
    typename std::vector<T, Alloc>::size_type new_size)
{
    v.resize(new_size); // simply forward
}

但是,如果你只想放入新的向量而不用担心自由或成员函数,另一种选择就是简单地继承std::vector

#include <vector>
#include <memory>

template<class T, class Alloc = std::allocator<T>>
class myvector
  : public std::vector<T, Alloc>
{
  typedef std::vector<T, Alloc> base;
public:
  typedef typename base::size_type size_type;

  void resize(size_type new_size){
    base::resize(new_size);
  }

  void resize(size_type new_size, T const& val){
    if (this->size() < new_size)
        this->insert(this->end(), new_size - this->size(), val);
    else if (new_size < this->size())
        this->erase(this->begin() + new_size, this->end());
  }
};

请注意,我还提供了resize的单个参数版本,因为两个参数版本将隐藏所有基类版本。另请注意,我需要使用this->为所有成员函数调用添加前缀,因为它们依赖于基类std::vector,并且在模板参数上也是如此。