在库的内部修复依赖项Fix your dependencies on library internals

05/24/2017

作者

本文内容

Microsoft 为标准库、绝大多数 C 运行时库和众多 Visual Studio 版本中的其他 Microsoft 库发布了源代码。Microsoft has published the source code for the Standard Library, most of the C Runtime Library, and other Microsoft libraries in many versions of Visual Studio.这一举措旨在帮助你了解库行为，并帮助调试代码。The intent is to help you understand library behavior and to debug your code.发布库源代码的一个副作用是它会暴露某些内部值、数据结构和函数，即使它们并非库接口的一部分。One side-effect of publishing the library source code is that some internal values, data structures, and functions are exposed, even though they are not part of the library interface.它们的名称通常以两道下划线开头，或一道下划线后跟一个大写字母，这种名字在 C++ 标准中予以保留并实现。They usually have names that begin with two underscores, or an underscore followed by a capital letter, names that the C++ Standard reserves to implementations.这些值、结构和函数是实现细节，有可能随时间过去、随库的发展而有所更改，因此我们强烈建议对它们不要有任何依赖项。These values, structures, and functions are implementation details that may change as the libraries evolve over time, and so we strongly recommend against taking any dependencies on them.如果执意如此，则将存在代码不可移植的风险，并且在将代码迁移至新版本的库时，还有可能出现问题。If you do, you risk non-portable code and issues when you try to migrate your code to new versions of the libraries.

在大多数情况下，每个 Visual Studio 版本的“新增功能”或“重大更改”文档都不会提到对库内部的更改。In most cases, the What's New or Breaking Changes document for each release of Visual Studio doesn't mention changes to library internals.毕竟你不应该被这些实现细节所影响。After all, you're not supposed to be affected by these implementation details.但有时，在要使用某些代码时，可以看见库的内部是十分大的。However, sometimes the temptation to use some code you can see inside the library is too great.本主题讨论 CRT 上的依赖项，或可能用到的标准库内部，以及如何更新代码以删除这些依赖项，从而使其更富可移植性，或使其得以迁移至新版本的库。This topic discusses dependencies on CRT or Standard Library internals you may have relied on, and how to update your code to remove those dependencies so you can make it more portable or migrate to new versions of the library.

如果要使用和 basic_string 相同的哈希代码机制将 const char * 序列加入无序的容器，则可利用使用 std::string_view 的 std::hash 模板重载，它将以可移植的方式返回哈希代码。If your intent is to put a const char * sequence into an unordered container by using the same hash code machinery as basic_string, you can do that by using the std::hash template overload that takes a std::string_view, which returns that hash code in a portable way.在未来，字符串库可能依赖（也可能不依赖） FNV-1a 哈希的使用，因此这是避免特定哈希算法上的依赖项的最佳方法。The string library code may or may not rely on use of an FNV-1a hash in the future, so this is the best way to avoid a dependency on a particular hash algorithm.

如果要通过任意内存生成 FNV-1a 哈希，则可使用 GitHub 上的 VCSamples 存储库的独立头文件 - fnv1a.hpp（在 MIT license 下）中的代码。If your intent is to generate an FNV-1a hash over arbitrary memory, we've made that code available on GitHub in the VCSamples repository in a stand-alone header file, fnv1a.hpp, under an MIT license.为方便起见，我们还在此处添加了副本。We've also included a copy here for your convenience.可将此代码复制到头文件，将标头添加到任何受影响的代码，然后通过 fnv1a_hash_bytes 查找和替换 _Hash_seq。You can copy this code into a header file, add the header to any affected code, and then find and replace _Hash_seq by fnv1a_hash_bytes.你将在 _Hash_seq 中获得与内部实现相同的行为。You'll get identical behavior to the internal implementation in _Hash_seq.

/*
VCSamples
Copyright (c) Microsoft Corporation
All rights reserved.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stddef.h>
inline size_t fnv1a_hash_bytes(const unsigned char * first, size_t count) {
#if defined(_WIN64)
static_assert(sizeof(size_t) == 8, "This code is for 64-bit size_t.");
const size_t fnv_offset_basis = 14695981039346656037ULL;
const size_t fnv_prime = 1099511628211ULL;
#else /* defined(_WIN64) */
static_assert(sizeof(size_t) == 4, "This code is for 32-bit size_t.");
const size_t fnv_offset_basis = 2166136261U;
const size_t fnv_prime = 16777619U;
#endif /* defined(_WIN64) */
size_t result = fnv_offset_basis;
for (size_t next = 0; next < count; ++next)
{ // fold in another byte
result ^= (size_t)first[next];
result *= fnv_prime;
}
return (result);
}