libstdc++中u8path弃用建议是否违反严格别名规则?
关于std::filesystem::u8path弃用后的替代方案疑问
背景
C++20已弃用std::filesystem::u8path,以下示例代码:
#include <filesystem> std::string foo(); int main() { auto path = std::filesystem::u8path(foo()); }
使用libstdc++ 13编译(开启编译选项-std=c++23 -Wall -Wextra -pedantic-errors -Wdeprecated)时,会触发如下弃用警告:
<source>:7:40: warning: 'std::filesystem::__cxx11::path std::filesystem::__cxx11::u8path( const _Source&) [with _Source = std::__cxx11::basic_string<char>; _Require = path; _CharT = char]' is deprecated: use 'path((const char8_t*)&*source)' instead [-Wdeprecated-decla rations] 7 | auto path = std::filesystem::u8path(foo()); | ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
警告中建议的转换path((const char8_t*)&*source)存在明显的严格别名违规,会导致未定义行为(UB),现针对以下问题寻求解答:
- 该判断是否正确?
- GCC是否提供了额外保证,使该转换合法?
- 若路径存储在
std::string中,不想全部改为std::u8string,是否有更优的替代方案?
解答
1. 该判断是否正确?
正确。根据C++标准的严格别名规则,除char、unsigned char和std::byte外,不能通过指向另一种类型的指针访问对象。将std::string(存储char类型)的内容强制转换为char8_t*访问,属于违反严格别名规则的行为,确实会导致未定义行为。
2. GCC是否提供了额外保证,使该转换合法?
GCC官方文档中并未针对该转换提供额外的合规保证。虽然在部分平台或禁用严格别名优化(-fno-strict-aliasing)的情况下,该转换可能不会引发实际问题,但这属于依赖编译器实现细节的非标准做法,不具备可移植性,也不符合C++标准要求。
3. 若路径存储在std::string中,不想全部改为std::u8string,是否有更优的替代方案?
推荐两种安全合规的替代方案:
- 方案一:构造
std::u8string传递给path
直接利用std::u8string的构造函数,将std::string的字节序列转换为UTF-8编码的std::u8string,再传递给std::filesystem::path,完全符合标准且无未定义行为:auto path = std::filesystem::path(std::u8string(source.begin(), source.end())); - 方案二:直接使用
path的原生编码构造函数
如果std::string中的路径是系统原生编码,可以直接传递给path的构造函数,标准库会自动处理编码转换;如果是UTF-8编码,也可通过std::string_view直接构造,但需确保编译器和标准库支持UTF-8路径的正确解析。相比之下,方案一的逻辑更明确,兼容性更强。
内容的提问来源于stack exchange,提问作者HolyBlackCat
相关产品推荐
相关产品推荐

