![](/img/trans.png)
[英]Difference between allocator supplied as template parameter and allocator supplied as constructor argument in C++ containers?
[英]C++ custom allocator size argument as template parameter throws compiler error
當我為我的容器使用自定義分配器時,以下代碼給了我預期的結果(保持大小 sz 作為全局變量)
#include <cstddef> /* size_t */
#include <new> /* Only for bad_alloc */
#include <vector>
using std::vector;
#include <iostream>
using std::cout;
using std::endl;
std::size_t constexpr sz = 4;
template <typename T> class StaticAllocator {
protected:
static T buf[sz];
public:
typedef T value_type;
T* allocate(std::size_t const n) {
if (n > sz) throw std::bad_alloc();
return buf;
}
void deallocate(T*, std::size_t) {}
};
template<typename T> T StaticAllocator<T>::buf[sz];
int main(void) {
std::vector<char, StaticAllocator<char> > v;
v.push_back('a');
v.push_back('b');
for (auto const& i : v) cout << i << endl;
}
當我嘗試使用大小作為類的模板參數時,此版本的代碼給了我編譯器錯誤
#include <cstddef> /* size_t */
#include <new> /* bad_alloc */
#include <vector>
using std::vector;
#include <iostream>
using std::cout;
using std::endl;
template<typename T, std::size_t sz> class StaticAllocator {
protected:
static T buf[sz];
public:
typedef T value_type;
T* allocate(std::size_t const n) {
if (n > sz) throw std::bad_alloc();
return buf;
}
void deallocate(T*, std::size_t) {}
};
template<typename T, std::size_t sz> T StaticAllocator<T, sz>::buf[sz];
int main(void) {
std::vector<char, StaticAllocator<char, 4> > v;
v.push_back('a');
v.push_back('b');
for (auto const& i : v) cout << i << endl;
}
要從類型T
的分配器獲取某種類型U
的分配器,使用成員別名模板std::allocator_traits::rebind_alloc<U>
[allocator.traits.types]:
Alloc::rebind<T>::other
如果Alloc::rebind<T>::other
有效並表示一個類型; 否則,Alloc<T, Args>
如果Alloc
是形式Alloc<U, Args>
的類模板實例化,其中Args
是零個或多個類型參數; 否則,rebind_alloc
的實例化是rebind_alloc
。
請注意, Args
是類型模板參數。 在您的分配器中沒有rebind
。 在第一種情況下,使用Alloc<U>
, Args
為空。 但是在第二種情況下,第二個模板參數是非類型參數,它不能被Args
匹配。
您需要手動添加rebind
成員結構:
template<typename T, std::size_t sz>
class StaticAllocator {
// ...
template<class U>
struct rebind {
using other = StaticAllocator<U, sz>;
};
};
另請注意,對於某些通用類型S
,您的分配器已損壞。 首先,默認情況下會初始化buf
構造sz
對象S
。 然后,在破壞現有的之前,它將通過在同一位置新構造S
來覆蓋它。 類似的事情發生在重新分配時。 這可能會導致未定義的行為。 有關詳細信息,請參閱此問題和此問題。
在現已刪除的答案中提出了以下解決方案:從std::allocator<T>
繼承:
template<typename T, std::size_t sz> class StaticAllocator :
public std::allocator<T> {
// ...
};
代碼編譯並運行,但是... StaticAllocator::allocate
和StaticAllocator::deallocate
沒有被調用(至少在 libstdc++ 中)。 原因是內部std::vector
總是使用rebind
來獲取分配器類型:
using Tp_alloc_type =
typename gnu_cxx::alloc_traits<Alloc>::template rebind<Tp>::other;
rebind
繼承自std::allocator<T>
並返回std::allocator
而不是StaticAllocator
。 這就是為什么您仍然必須在StaticAllocator
提供自己的rebind
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.