将一些代码移植到 VS 不起作用,因为 std::allocator 的实现不能正确支持具有状态的分配器。
从在 gcc 和 clang 上运行良好的代码示例来看,MS 似乎尝试实际创建 3 个分配器而不是 1 个。
谢谢!
示例(基于 https://en.cppreference.com/w/cpp/named_req/Allocator 中的代码)。 下面是一些在 clang 和 gcc 中可以正常工作但在 VS 中不能正常工作的代码:
//----------------------开始代码示例-------------------- -------------------
#include <cstdlib>
#include <iostream>
#include <limits>
#include <new>
#include <vector>
#include <list>
using namespace std;
int n=0;
template<class T>
struct Mallocator
{
typedef T value_type;
int i;
Mallocator() {
i = n++;
cout << "Mallocator::Mallocator " << i << endl;
}
~Mallocator() {
cout << "Mallocator::~" << i << endl;
}
template<class U>
constexpr Mallocator(const Mallocator <U>&u) noexcept {
i = n++;
cout << "Mallocator(const Mallocator <U>&) u.i=" << u.i << ", i=" << i << endl;
}
[[nodiscard]] T* allocate(std::size_t n)
{
if (n > std::numeric_limits<std::size_t>::max() / sizeof(T))
throw std::bad_array_new_length();
if (auto p = static_cast<T*>(std::malloc(n * sizeof(T))))
{
report(p, n);
return p;
}
throw std::bad_alloc();
}
void deallocate(T* p, std::size_t n) noexcept
{
report(p, n, 0);
std::free(p);
}
private:
void report(T* p, std::size_t n, bool alloc = true) const
{
std::cout << "i=" << i << " " << (alloc ? "Alloc: " : "Dealloc: ") << sizeof(T) * n
<< " bytes at " << std::hex << std::showbase
<< reinterpret_cast<void*>(p) << std::dec << '\n';
}
using is_always_equal = false_type;
using propagate_on_container_move_assignment = false_type;
};
int main()
{
list<int, Mallocator<int>> l; // = {1,2,3,4};
l.push_back(1);
l.push_back(2);
l.push_back(3);
list<int, Mallocator<int>> l2;
for(auto item : l)
l2.push_back(item);
cout << "------------" << endl;
}
//---------------------- end example code -----------------------------
在 https://coliru.stacked-crooked.com/view?id=f612fb49665239e2 上运行时 结果:
g++ -std=c++20 -O2 -Wall -Wextra -pedantic -pthread -pedantic-errors main.cpp -lm -latomic && ./a.out
Mallocator::Mallocator 0
i=0 Alloc: 24 bytes at 0x1bed030
i=0 Alloc: 24 bytes at 0x1bed050
i=0 Alloc: 24 bytes at 0x1bed070
Mallocator::Mallocator 1
i=1 Alloc: 24 bytes at 0x1bed090
i=1 Alloc: 24 bytes at 0x1bed0b0
i=1 Alloc: 24 bytes at 0x1bed0d0
------------
i=1 Dealloc: 24 bytes at 0x1bed090
i=1 Dealloc: 24 bytes at 0x1bed0b0
i=1 Dealloc: 24 bytes at 0x1bed0d0
Mallocator::~1
i=0 Dealloc: 24 bytes at 0x1bed030
i=0 Dealloc: 24 bytes at 0x1bed050
i=0 Dealloc: 24 bytes at 0x1bed070
Mallocator::~0
可以看到,有 2 个分配器,每个分配器负责自己的项目
在 VS 版本 17.8.5 上的新控制台应用程序上运行的相同代码给出了非常不同的结果,创建了一些 6 (!!!) 分配器,并且似乎 using is_always_equal = false_type; 完全被忽略了! 使用默认和 CPP+20 变体进行测试 - 同样的问题。
//------------- VS 17.8.5 输出---------
Mallocator::Mallocator 0
Mallocator(const Mallocator <U>&) u.i=0, i=1
i=1 Alloc: 16 bytes at 0000026F18612BF0
i=0 Alloc: 24 bytes at 0000026F1860EE10
Mallocator::~1
i=0 Alloc: 24 bytes at 0000026F1860EDB0
i=0 Alloc: 24 bytes at 0000026F1860F470
i=0 Alloc: 24 bytes at 0000026F1860F530
Mallocator::Mallocator 2
Mallocator(const Mallocator <U>&) u.i=2, i=3
i=3 Alloc: 16 bytes at 0000026F18612C40
i=2 Alloc: 24 bytes at 0000026F1860F590
Mallocator::~3
i=2 Alloc: 24 bytes at 0000026F1860EB10
i=2 Alloc: 24 bytes at 0000026F1860F5F0
i=2 Alloc: 24 bytes at 0000026F1860F650
------------
i=2 Dealloc: 24 bytes at 0000026F1860EB10
i=2 Dealloc: 24 bytes at 0000026F1860F5F0
i=2 Dealloc: 24 bytes at 0000026F1860F650
i=2 Dealloc: 24 bytes at 0000026F1860F590
Mallocator(const Mallocator <U>&) u.i=2, i=4
i=4 Dealloc: 16 bytes at 0000026F18612C40
Mallocator::~4
Mallocator::~2
i=0 Dealloc: 24 bytes at 0000026F1860EDB0
i=0 Dealloc: 24 bytes at 0000026F1860F470
i=0 Dealloc: 24 bytes at 0000026F1860F530
i=0 Dealloc: 24 bytes at 0000026F1860EE10
Mallocator(const Mallocator <U>&) u.i=0, i=5
i=5 Dealloc: 16 bytes at 0000026F18612BF0
Mallocator::~5
Mallocator::~0
_ITERATOR_DEBUG_LEVEL=1
和2
导致了这种奇怪的现象。将其设置为 0
(这是发布模式下的默认设置)给我一个很好的输出(除了他们为每个列表分配一个额外的节点)。
也许他们这样做是为了帮助您检查分配器(分配器的副本应该能够与原始内存一起工作),或者 MSVC STL 只是有错误。
输出带有
_ITERATOR_DEBUG_LEVEL=0
:
i=0 Alloc: 24 bytes at 00007FFFFE7B2A40
i=0 Alloc: 24 bytes at 00007FFFFE7B2AA0
i=0 Alloc: 24 bytes at 00007FFFFE7B2B00
i=0 Alloc: 24 bytes at 00007FFFFE7B2B60
Mallocator::Mallocator 1
i=1 Alloc: 24 bytes at 00007FFFFE7B2BC0
i=1 Alloc: 24 bytes at 00007FFFFE7B2C20
i=1 Alloc: 24 bytes at 00007FFFFE7B2C80
i=1 Alloc: 24 bytes at 00007FFFFE7B2CE0
------------
i=1 Dealloc: 24 bytes at 00007FFFFE7B2C20
i=1 Dealloc: 24 bytes at 00007FFFFE7B2C80
i=1 Dealloc: 24 bytes at 00007FFFFE7B2CE0
i=1 Dealloc: 24 bytes at 00007FFFFE7B2BC0
Mallocator::~1
i=0 Dealloc: 24 bytes at 00007FFFFE7B2AA0
i=0 Dealloc: 24 bytes at 00007FFFFE7B2B00
i=0 Dealloc: 24 bytes at 00007FFFFE7B2B60
i=0 Dealloc: 24 bytes at 00007FFFFE7B2A40
Mallocator::~0