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

发布于 2025-01-08 12:14:32 字数 1283 浏览 6 评论 0原文

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

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

我正在寻找一个编写良好、经过充分测试、独立且与 STL 兼容的 std::vector 实现,并具有 MIT 风格的许可证,我可以作为对齐类型的首选容器放入我的项目中。

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

(我对 std::vector 的合理子集的实现非常满意,该子集仅支持 push_backclear容量大小保留调整大小交换和数组索引。)

有什么想法吗?

The implementation of std::vector that ships with Visual Studio 2010 and earlier versions has a well known particularity: the resize method has the following signature (C++03-compliant):

void resize(size_type new_size, value_type value);

instead of the C++11-compliant signature that's been used by the majority of other STL implementations (like gcc's STL or STLport) long before C++11:

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

The problem with the first variant is that, in some situations, it will fail to compile if value_type has an alignment specification:

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

This is a well known problem with no satisfactory workaround apart from using a different implementation of std::vector.

I'm looking for a well-written, well-tested, self-contained and STL-compatible implementation of std::vector with a MIT-style licence that I could drop into my project as a container of choice for aligned types.

I considered extracting it from STLport or gcc's STL but, being fully standard-compliant, they're both large with many non-trivial dependencies.

(I would be perfectly happy with an implementation of a reasonable subset of std::vector that would only support push_back, clear, capacity, size, reserve, resize, swap and array indexing.)

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

肥爪爪 2025-01-15 12:14:32

Eigen 库背后的人似乎找到了一个很好的解决方法来解决存储“过度对齐类型”的问题(Stephan T. Lavavej 称之为std::vector 在 Visual Studio 的 STL 中实现。

他们的实现似乎不必要的复杂(检查来源此处此处),但主要思想是封装进入 < 的类型code>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用于 Eigen::aligned_allocator_indirection 分配器的 std::vector ...

欢迎提供线索。关键是,这个技巧非常有效(据我所知),除了稍微不雅之外,我没有发现它有任何问题。

The guys behind the Eigen library seem to have found a nice workaround for the problem of storing "overly-aligned types" (as Stephan T. Lavavej call them) into a std::vector as implemented in Visual Studio's STL.

Their implementation seems unnecessary complicated (check the sources here and here) but the main idea is to encapsulate the type that goes into the std::vector with a thin wrapper:

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

About the implementation in Eigen, I must admit I don't quite understand

  • why they need Eigen::aligned_allocator_indirection,
  • why they need to make an exception for arithmetic types in EIGEN_WORKAROUND_MSVC_STL_SUPPORT,
  • why they need to define all these constructors and operators in Eigen::workaround_msvc_stl_support,
  • or why they need to redefine resize in their partial specialization of std::vector for the Eigen::aligned_allocator_indirection allocator...

Clues welcome. The point is, this trick works perfectly (as far as I can tell) and I don't see anything wrong with it, apart maybe from the slight inelegance.

逆夏时光 2025-01-15 12:14:32

最简单(也是最好的,恕我直言)的选择是提供一个免费函数作为向量接口的扩展,它做了正确的事情。您需要实现 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 的单参数版本code>,因为两个参数版本将隐藏所有基类版本。另请注意,我需要在所有成员函数调用前加上 this-> 前缀,因为它们依赖于基类 std::vector,因此也依赖于模板论据。

The easiest (and best, imho) option would be to provide a free function as an extension to the vector interface, which does the right thing. The functions you need to implement resize are all available from the public interface of 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());
}

And for consistency also the single argument version:

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
}

If you, however, just want to drop-in the new vector and never worry about free or member function, another option is to simply subclass 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());
  }
};

Note that I also provided the single argument version of resize, since the two argument version would hide all base-class versions. Also note that I needed to prefix all member function calls with this->, since they are dependent on the base class std::vector, and as such on the template arguments.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文