Confirm This Standard Library Bug Relating to Allocators in MSVC 2015 RC
Asked Answered
P

1

6

Here is a SSCCE:

#include <memory>
#include <vector>

template <class T> struct my_allocator : std::allocator<T> {
    //This overriding struct causes the error
    template <class U> struct rebind {
        typedef my_allocator<T> other;
    };

    //Ignore all this.
    typedef std::allocator<T> base;
    typename base::pointer allocate(typename base::size_type n, std::allocator<void>::const_pointer /*hint*/=nullptr) { return (T*)malloc(sizeof(T)*n); }
    void deallocate(typename base::pointer p, typename base::size_type /*n*/) { free(p); }
};

int main(int /*argc*/, char* /*argv*/[]) {
    std::vector<int,my_allocator<int>> vec;
    return 0;
}

GCC likes it.
ICC likes it.
Clang likes it.
Even MSVC 2013 likes it.
But MSVC 2015 RC spits out:

1>------ Build started: Project: Test Alloc, Configuration: Debug Win32 ------
1>  main.cpp
1>c:\program files (x86)\microsoft visual studio 14.0\vc\include\vector(579): error C2664: 'void std::_Wrap_alloc<my_allocator<int>>::deallocate(int *,unsigned int)': cannot convert argument 1 from 'std::_Container_proxy *' to 'int *'
1>  c:\program files (x86)\microsoft visual studio 14.0\vc\include\vector(579): note: Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1>  c:\program files (x86)\microsoft visual studio 14.0\vc\include\vector(574): note: while compiling class template member function 'void std::_Vector_alloc<std::_Vec_base_types<_Ty,_Alloc>>::_Free_proxy(void)'
1>          with
1>          [
1>              _Ty=int,
1>              _Alloc=my_allocator<int>
1>          ]
1>  c:\program files (x86)\microsoft visual studio 14.0\vc\include\vector(541): note: see reference to function template instantiation 'void std::_Vector_alloc<std::_Vec_base_types<_Ty,_Alloc>>::_Free_proxy(void)' being compiled
1>          with
1>          [
1>              _Ty=int,
1>              _Alloc=my_allocator<int>
1>          ]
1>  c:\program files (x86)\microsoft visual studio 14.0\vc\include\vector(668): note: see reference to class template instantiation 'std::_Vector_alloc<std::_Vec_base_types<_Ty,_Alloc>>' being compiled
1>          with
1>          [
1>              _Ty=int,
1>              _Alloc=my_allocator<int>
1>          ]
1>  c:\users\ian mallett\desktop\test-alloc\main.cpp(18): note: see reference to class template instantiation 'std::vector<int,my_allocator<int>>' being compiled

Related program give similarly fishy sounding errors. Here are two:
error C2664: 'void std::_Wrap_alloc>::deallocate(int *,unsigned int)': cannot convert argument 1 from 'std::_Container_proxy *' to 'int *'
cannot convert argument 1 from 'std::_Wrap_alloc>' to 'const aligned_allocator &'

Boolean question: is this a bug? Iff it is, I will (try) to submit it.

[EDIT: as noted in the comments, this only occurs in debug mode. In release mode, it compiles and executes fine.] [EDIT: much simpler example]

Physic answered 19/7, 2015 at 5:50 Comment(7)
Might be irrelevant, but adding declarations to namespace std is UB.Ballentine
@Ballentine That's not true. There are exceptions, see Extending the namespace std.Lentha
@CaptainObvlious I don't think any of these exceptions apply here.Ballentine
What if you turn off the diagnostic mode of the MSVC standard library?Crispi
I have edited the question to not put code in std::; the error still occurs. @UlrichEckhardt running in release mode causes it to compile/run successfully.Physic
It is just buggy code, you don't support rebind. Many places where you can find out how to create your own allocator type, nothing that should ever be repeated here :)Mango
My guess is that the diagnostic mode wraps your allocator to trap misuses. Assuming @Hans Passant is right (I have honestly no experience with implementing STL-style allocators), a functioning rebind() implementation in your allocator might be necessary for that, which would explain this behaviour and make it a bug in your code indeed. Have you tried diagnostic mode for other standard libraries (#define _GLIBCXX_DEBUG)?Crispi
P
6

Boolean question: is this a bug?

false.


Although the template error given by MSVC here is surpassingly unhelpful, the error here is mine (reassuring since this version of the standard library is shipping today).

I created this allocator (and later, the reduced test case) from a variety of sources, which is why I assumed it was correct. However, as suggested in the comments, I checked again, this time exhaustively against the documentation.

The missing component here is one of the copy constructors (the template one that can't be auto-generated). This only shows up when the rebind struct is defined since the rebind struct overrides the same struct in the parent class (which, since it's in the parent class, ultimately causes the parent's copy constructor to be called, so there's no problem (except that it's technically wrong)).


The interesting thing here is that the error didn't occur until now. As I said, GCC, Clang, and MSVC 2013 all like it (even with their respective debug modes). It's just that none of these happened to call the template copy constructor. Nevertheless, it is specified by the standard, so again, the error is ultimately mine.

Congratulations to the MSVC compiler team, and sorry for the noise! :D

Physic answered 20/7, 2015 at 18:9 Comment(1)
Thanks for the clear answer, I ran into the exact same problem and you probably saved me some hours!Abrego

© 2022 - 2024 — McMap. All rights reserved.