[cfe-users] bug in libc++
clang at lucena.com
Fri Oct 4 15:54:46 PDT 2013
On Oct 3, 2013, at 2:58 PM, Manu <monamimani at gmail.com> wrote:
> I thought that std::vector would have a noexcept move constructor and assignment given that all of it's member are noexcept in regard of move construction and assignment. Then again, i forgot about the allocator. But that mean that the default allocator is not noexcept when doing a move construction of assignment?
> When we do a move construction or assignment of a vector with the default allocator, there shouldn't be any actual heap allocation going on. no?
> Also if it now crash thats is new. I am synched from about 3 days ago and it was compiling with error but not crashing.
My initial response was based on the spec - neither vector’s move constructor nor its move-assignment operator are required to be noexcept (true). However, looking at the source for libc++, I see that both of those special member functions have optional noexcept specifications; so when using libc++, at least, it’s possible for std::vector to be nothrow in these cases.
Poking around with your example, I noticed a few interesting things:
* is_nothrow_move_constructible and is_nothrow_move_assignable both return true for std::basic_string <char>, std::string, and std::vector <std::string>. For that matter, so does std::allocator when templatized on each of those classes. Just to be absolutely certain of this last case, I also checked std::__1::is_nothrow_move_constructible <std::__1::allocator <std::__1::basic_string <char>>> and it’s still true.
* The compiler complains about your Foo class, essentially claiming that is_nothrow_move_constructible <std::allocator <string>> is false.
So, yeah, a conflict.
A few things to note: std::allocator explicitly defines a copy constructor but no copy-assignment operator. This means that its move constructor and move-assignment operator are implicitly deleted (and that the copy-assignment operator is implicitly defined, though this behavior is deprecated). That means any time you invoke a move special member function, you’re actually getting the copy special member function. In the case of a class like vector, this behavior shouldn’t be a problem for moves since the allocator doesn’t actually get moved/copied - it’s more of a policy class.
All I can figure here is that the noexcept specification is tripping on the allocator type traits because it’s checking them before it has full “visibility” of allocator’s implicit special member functions. I don’t know enough about noexcept to know exactly what’s happening, but my gut feeling, based on explicit testing with is_nothrow_xxx, is that this is a subtle clang bug after all (or possibly an abuse of noexcept specifications by libc++). It would be nice if an actual expert would weigh in, though.
More information about the cfe-users