c++templateschromiumpdfium

static_assert fails in conjunction with std::vector with a custom allocator


I am trying to compile PDFium taken from the chromium source code with MSVC 141. The code is a custom allocator. You can see that the custom allocator can be instantiated with wchar_t no problem. wchar_t is apparently arithmetic. However, passing it into a vector fails the static assertions. The following code gives a static assertion, which I do not expect:

#include <iostream>
#include <type_traits>
#include <vector>

template <typename T>
struct FxAllocAllocator {
public:
    static_assert(std::is_arithmetic<T>::value,
        "Only numeric types allowed in this partition");

    using value_type = T;
    using pointer = T*;
    using const_pointer = const T*;
    using reference = T&;
    using const_reference = const T&;
    using size_type = size_t;
    using difference_type = ptrdiff_t;

    template <typename U>
    struct rebind {
        using other = FxAllocAllocator<U>;
    };

    FxAllocAllocator() noexcept = default;
    FxAllocAllocator(const FxAllocAllocator& other) noexcept = default;
    ~FxAllocAllocator() = default;

    template <typename U>
    FxAllocAllocator(const FxAllocAllocator<U>& other) noexcept {}

    pointer address(reference x) const noexcept { return &x; }
    const_pointer address(const_reference x) const noexcept { return &x; }
    pointer allocate(size_type n, const void* hint = 0) {
        return static_cast<pointer>(FX_AllocOrDie(n, sizeof(value_type)));
    }
    void deallocate(pointer p, size_type n) { FX_Free(p); }
    size_type max_size() const noexcept {
        return std::numeric_limits<size_type>::max() / sizeof(value_type);
    }

    template <typename U, typename... Args>
    void construct(U* p, Args&&... args) {
        new (reinterpret_cast<void*>(p)) U(std::forward<Args>(args)...);
    }

    template <typename U>
    void destroy(U* p) {
        p->~U();
    }

    // There's no state, so they are all the same,
    bool operator==(const FxAllocAllocator& that) { return true; }
    bool operator!=(const FxAllocAllocator& that) { return false; }
};

int main()
{
    std::cout << "wchar_t:           " << std::is_arithmetic<wchar_t>::value << '\n';

    FxAllocAllocator<uint8_t> success;
    std::vector<wchar_t, FxAllocAllocator<wchar_t>> fail;
}

This is beyond my skills to figure out. My guess so far is that the MSVC compiler works differently than GCC, or I am missing a compiler option. I've tried MSVC 141 and 142. C++11 up to c++17. Can anyone explain to my why this does not compile?


Solution

  • It seems that the Visual Studio debug runtime code has a section in the destructor of std::vector that assumes iterator debugging. I can't post the code here, due to probable copyright issues.

    My guess is that the debug runtime expects the allocators to be stock Visual C++ allocators, with debugging information. Someone will correct me if I'm wrong, but this is where the static_assert is pointing to.

    What you can do is build a Release mode only, since a release build does not invoke the debug library code.

    However, if you desire to easily debug the application you can:

    1) Set the iterator level to 0 (_ITERATOR_DEBUG_LEVEL preprocessor symbol should be 0) and rebuild

    or

    2) Create another configuration (call it Release With Debug) and copy the same settings for Release, except that the optimizations should be turned off.