为具有替换operator new的类定制std::allocator

3

我最近使用SSE替换了一些向量/矩阵类,并确保内存正确对齐。

遵循此问题答案中的建议,我已经为需要它的类替换了operator new/delete,并开始编写自定义分配器来与STL容器一起使用,但是两者之间似乎存在一些冲突:

为了开始,我只是从这里复制并粘贴了样例分配器类。当我将它用于std::vector中的相关类型时,没有使用我的自定义new/delete时,它可以编译通过。但是当我替换那些函数时,在construct()函数中出现错误“no matching function for call to 'operator new'”。

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

我猜我替换了“通常”的new,这可能使放置new变得模糊了?然而,考虑到我无法编写自己的放置new以供其选择,我真的不知道该怎么办... 我是整个自定义内存分配事情的新手,所以任何建议都将不胜感激!我正在使用Clang v3.4(或gcc 4.1.2)在Linux上进行编译;不使用C ++ 11。谢谢。
3个回答

4
经典的allocator::construct调用::new((void *)p) T(val) 通过省略::,您让名称查找从T类范围开始,在那里它找到了您的类作用域下的operator new并且没有继续查找(名称查找在第一个发现匹配名称的范围中停止,即使更好的候选项存在于一些封闭范围中)
(对void的转换是为了防止用户偷偷添加一个全局的几乎放置新重载,该重载采用非void指针参数)
PS:正如评论中正确指出的那样,“鉴于我不能编写自己的放置新内容”是错误的假设。您无法替换全局放置新内容,但您肯定可以编写特定于类的放置新内容,然后由类范围查找选取。请参考cppreference了解分配函数的概述。

为了解决这个问题,可以使用 ::new 或者为你的类实现一个重载的定位 new - Yakk - Adam Nevraumont
啊,是的,这很有道理...谢谢!出于某种原因,我完全忽视了ccpreference中指出这一点的注释:“虽然无法替换放置new(重载5和6),但可以按照上面所述在类作用域中定义具有相同签名的函数”...糟糕。 - YamLady

1

我建议使用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)。

0

我会使用这里提供的分配器作为起点:http://en.cppreference.com/w/cpp/concept/Allocator。实际上,这是一个最小的分配器。特别地,你不需要写construct。如果allocator_traits没有发现你的分配器有construct方法,它将为你调用放置new,正确地使用::(如Cubbi所述)来限定调用,因此你不会遇到这个问题:http://en.cppreference.com/w/cpp/memory/allocator_traits/construct

我可能根本不会编写自定义的new/delete。只需编写自定义分配器,并使你的Vector/Matrix类通过使用你的自定义分配器管理其数据即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接