我能够使用自定义分配器实现检索当前已分配数组的功能。以下代码展示了这个概念:
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <cassert>
#include <cstring>
#include <memory>
#include <stdexcept>
#include <vector>
#include <iostream>
template <typename T>
struct MyAllocation
{
size_t Size = 0;
std::unique_ptr<T> Ptr;
MyAllocation() { }
MyAllocation(MyAllocation && other) noexcept
: Ptr(std::move(other.Ptr)), Size(other.Size)
{
other.Size = 0;
}
};
template <typename T>
class MyAllocator
{
public:
using value_type = T;
private:
struct Allocator
{
[[nodiscard]] T* allocate(std::size_t n)
{
T *ret = new T[n];
if (!(Current.Ptr == nullptr || CurrentDeallocated))
{
Current.Ptr.release();
}
Current.Ptr.reset(ret);
Current.Size = n;
CurrentDeallocated = false;
return ret;
}
void deallocate(T* p, std::size_t n)
{
(void)n;
if (Current.Ptr.get() == p)
{
CurrentDeallocated = true;
return;
}
delete[] p;
}
MyAllocation<T> Current;
bool CurrentDeallocated = false;
};
public:
MyAllocator()
: m_allocator(std::make_shared<Allocator>())
{
std::cout << "MyAllocator()" << std::endl;
}
template<class U>
MyAllocator(const MyAllocator<U> &rhs) noexcept
{
std::cout << "MyAllocator(const MyAllocator<U> &rhs)" << std::endl;
m_allocator = reinterpret_cast<const MyAllocator<T> &>(rhs).m_allocator;
}
MyAllocator(const MyAllocator &rhs) noexcept
: m_allocator(rhs.m_allocator)
{
std::cout << "MyAllocator(const MyAllocator &rhs)" << std::endl;
}
public:
T* allocate(std::size_t n)
{
std::cout << "allocate(" << n << ")" << std::endl;
return m_allocator->allocate(n);
}
void deallocate(T* p, std::size_t n)
{
std::cout << "deallocate(\"" << p << "\", " << n << ")" << std::endl;
return m_allocator->deallocate(p, n);
}
MyAllocation<T> release()
{
if (!m_allocator->CurrentDeallocated)
throw std::runtime_error("Can't release the ownership if the current pointer has not been deallocated by the container");
return std::move(m_allocator->Current);
}
public:
std::shared_ptr<Allocator> m_allocator;
};
template <class T, class U>
bool operator==(const MyAllocator<T>&, const MyAllocator<U>&) { return false; }
template <class T, class U>
bool operator!=(const MyAllocator<T>&, const MyAllocator<U>&) { return true; }
int main()
{
MyAllocator<char> allocator;
{
std::vector<char, MyAllocator<char>> test(allocator);
test.resize(5);
test.resize(std::strlen("Hello World") + 1);
std::strcpy(test.data(), "Hello World");
std::cout << "Current buffer: " << test.data() << std::endl;
test.pop_back();
test.push_back('!');
test.push_back('\0');
try
{
(void)allocator.release();
}
catch (...)
{
std::cout << "Expected throw on release() while the container has still ownership" << std::endl;
}
}
auto allocation = allocator.release();
std::cout << "Final buffer: " << allocation.Ptr.get() << std::endl;
return 0;
}
在 MSVC15 (VS2017)、gcc 和clang 上进行了测试。输出基本上取决于std::vector
的STL实现以及启用调试编译等小差异:
MyAllocator()
MyAllocator(const MyAllocator &rhs)
allocate(5)
allocate(12)
deallocate("", 5)
Current buffer: Hello World
allocate(18)
deallocate("Hello World!", 12)
Expected throw on release() while the container has still ownership
deallocate("Hello World!", 18)
Final buffer: Hello World!
std::vector
对象呢?我认为您会发现为此实现“release”非常困难。 - tadmanstd::vector
是否以一种简单的delete []
无法处理的方式来处理销毁? - Emerald Weaponstd::vector
无关的类中。我认为STL相关的移动语义修改过于保守。还有一些细节需要解决,例如如何传递有关分配器的信息。但我想如果release返回一个unique_ptr
或shared_ptr
,那么这个问题就可以解决。(https://dev59.com/AZHea4cB1Zd3GeqPnlNV) - alfC