簡體   English   中英

C++ 自定義分配器大小參數作為模板參數引發編譯器錯誤

[英]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::allocateStaticAllocator::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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM