Consider this simple program:
#include <string>
#include <sparsehash/dense_hash_map>
int main()
{
google::dense_hash_map<std::string, int> map;
map["foo"] = 0;
}
Compiling with GCC 8.2 and -Wclass-memaccess
(or -Wall
) produces a warning:
sparsehash/internal/libc_allocator_with_realloc.h:68:40: warning:
‘void* realloc(void*, size_t)’ moving an object of non-trivially copyable type
‘struct std::pair<const std::__cxx11::basic_string<char>, int>’;
use ‘new’ and ‘delete’ instead [-Wclass-memaccess]
return static_cast<pointer>(realloc(p, n * sizeof(value_type)));
~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
The questions are:
- Is it undefined behavior?
- Can you suggest a fix or workaround which can be applied to the application code (not by changing Sparsehash or avoiding its use)?
- (Bonus points) can you construct a program which actually misbehaves due to this (using std::string or your own nontrivial type)? So far I haven't seen any problems in code using std::string as the key type, despite the fact that std::string must be quite a commonly used key type.
I've filed an issue here: https://github.com/sparsehash/sparsehash/issues/149
Yes, it is undefined behavior.
But don't despair yet, iff
std::string
doesn't store any internal pointers in your implementation, nor registers them anywhere, it will "work" anyway; making a bitwise copy will be equivalent to move-construction at the destination and destructing the source.Such is the case for most (not all) string-implementations, SSO or not.
If you might use a type not guaranteed to be trivially destructively-moveable, use a different allocator (last template-argument) to avoid bitwise-moves.
Making a program blow up due to invalid moveing by bitwise copy is trivial.
Use this type with
google::dense_hash_map
: