【问题标题】:Undefined Behavior When Serializing filesystem::path Object [duplicate]序列化文件系统::路径对象时的未定义行为[重复]
【发布时间】:2021-09-04 21:36:55
【问题描述】:

在测试 filesystem::path 对象的序列化和反序列化时,我有以下代码可以正常工作:

#include <filesystem>
#include <array>
#include <iostream>

int main() {
    namespace fs = std::filesystem;
    std::array<char, sizeof(fs::path)> arr;
    fs::path currentPath("./Icon");
    memcpy(&arr[0], &currentPath, sizeof(fs::path));
    currentPath = fs::path("./Characters");         //Change currentPath before performing memcpy deserializing for testing purposes
    memcpy(&currentPath, &arr[0], sizeof(fs::path));
    std::cout << currentPath.filename();
}

这完美地工作,序列化到字节数组并按预期反序列化。直到我使用不同的文件路径,例如用下面的测试路径交换初始路径:

#include <filesystem>
#include <array>
#include <iostream>

int main() {
    namespace fs = std::filesystem;
    std::array<char, sizeof(fs::path)> arr;
    fs::path currentPath("./Characters");
    memcpy(&arr[0], &currentPath, sizeof(fs::path));
    currentPath = fs::path("./Icon");                   //Change currentPath before performing memcpy deserializing for testing purposes
    memcpy(&currentPath, &arr[0], sizeof(fs::path));
    std::cout << currentPath.filename();
}

当我运行这个版本的代码时,currentPath 对象最终被破坏了。

两个不同但真实的目录的不同行为使我相信未定义的行为已在某处溜走,但我不确定确切的位置。同样,文件路径中使用的目录是真实的,但即使不是,我也看不出它为什么会影响路径对象的序列化和反序列化,因为路径对象可用于表示不存在的文件路径。

【问题讨论】:

  • “这很完美”。它可能看起来有效,但它也是错误的,fs::path 不可轻易复制。
  • 由于fs::path 是固定大小的,问问自己它如何支持任意大小的路径。唯一可行的方法是包含一个指向堆分配内存的动态容器。因此,您不能复制内存并将其视为已序列化。请改用适当的序列化库/格式。
  • 作为一个近似的类比,阅读这个问题:How do I save and load a std::string with object serialization in C++?
  • @Jarod42 对象规范是否包含声明对象不可轻易复制的信息?在我使用任何东西之前,我通常会查看 cppreference.com 提供的文档,但我没有在 path 类中看到任何表明它不可轻易复制的内容。
  • 对于你不同的行为,也许path使用了小字符串优化...

标签: c++ serialization path c++17 undefined-behavior


【解决方案1】:

此答案适用于 libcxx std::filesystem (Clang),但我认为其他 STL 实现也有相同的:

这意味着当您执行currentPath = fs::path("./Icon"); 时,现有字符串被std::stringoperator= 释放,并且您隐藏的指针变得无效。它是否包含任何可识别的值取决于许多因素,包括可能的小字符串优化、其他线程的活动和愚蠢的运气。

如果您在 Clang 的 AddressSanitizer 下运行此代码,它会以大致相同的论点对您大喊大叫。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-03
    • 2014-08-16
    • 1970-01-01
    • 1970-01-01
    • 2012-07-29
    • 2016-07-04
    相关资源
    最近更新 更多