为具有已替换运算符new的类自定义std::分配器

Custom std::allocator for classes with replaced operator new

本文关键字:自定义 std 分配器 new 替换 运算符      更新时间:2023-10-16

我最近用使用SSE的类替换了一些Vector/Matrix类,现在正在确保内存正确对齐。

根据这个问题答案中的建议,我已经为需要它的类替换了运算符new/delete,并开始开发一个用于STL容器的自定义分配器——然而,两者之间似乎存在一些冲突:

首先,我只是从这里复制并粘贴了示例分配器类,当我在没有自定义new/delete的情况下将其与所讨论类型的std::vector一起使用时,它会编译得很好,但当我替换这些函数时,我会从construct()函数中得到一个错误"没有匹配的函数可以调用‘operator new’"

void    construct(pointer p, const T& t)    { new(p) T(t); }

我想我已经取代了"通常"的新位置,这在某种程度上掩盖了新位置?然而,考虑到我不能为它编写自己的新位置,我真的不知道该怎么办……我是整个自定义内存分配的新手,所以任何建议都将不胜感激!

我在Linux上使用Clang v3.4(或gcc 4.1.2)进行编译;不使用C++11。

非常感谢。

规范分配器::construct调用::new((void *)p) T(val)

通过省略::,您已经让名称查找从T的类作用域开始,在那里它找到了您的类范围的operator new,并且不再继续(名称查找停止在找到任何匹配名称的第一个作用域,即使在某些封闭作用域中存在更好的候选者)

(强制转换为void是为了防止用户偷偷进入全局几乎放置的新重载,该重载采用非void指针参数)

附言:正如评论中正确指出的那样,"鉴于我不能写自己的新职位"是错误的假设。您不能替换全局新放置,但您可以编写特定于类的新放置,然后通过类范围查找来获取。有关分配函数的摘要,请查看cppreference。

我建议使用Boost的aligned_allocator:

#include <boost/align/aligned_allocator.hpp>
#include <immintrin.h>
#include <vector>
struct m128i {
    // FIXME: ctors/opers with intrinsics would be nice (required?)
    __m128i data;
}
int main()
{
    std::vector<m128i, boost::alignment::aligned_allocator<m128i, 16> > v;
    v.emplace_back();
}

注意:我已经更新了它,使用了一个包装内部成员的结构。有很多图书馆这样做。这样做的原因很简单:vector_size属性将__m128i与__m256i与__m512i区分开来,模板忽略了类型属性,所以我相信它们最终都会使用相同的扩展,即"long-long"(在非I和d类型的情况下,则为float/double)。

我将使用我的起点作为这里给出的分配器:http://en.cppreference.com/w/cpp/concept/Allocator.它实际上是一个最小分配器。特别是,您根本不需要编写construct。如果allocator_traits没有发现您的分配器有construct方法,它只会为您调用placement new,用::正确地确定调用范围(正如Cubbi所指出的),这样您就不会有这个问题:http://en.cppreference.com/w/cpp/memory/allocator_traits/construct.

我可能根本不会写自定义的新/删除。只需编写一个自定义分配器,并让Vector/Matrix类使用自定义分配器通过std::vector管理它们的数据就足够了。