c++ - 如何用符合 C++ 核心准则的代码替换 C 风格的字符串解析?

标签 c++ parsing wavefront

以这两个代码片段为例:

//...
file_string = strstr(file_string, "\nv ");
while (file_string = strstr(file_string, "v ")) {
    vec::vec3<float> buffer = { 0.0f };
    file_string += strlen("v ");
    file_string = std::from_chars(file_string, file_string_end, buffer.x).ptr;
    file_string++;
    file_string = std::from_chars(file_string, file_string_end, buffer.y).ptr;
    file_string++;
    file_string = std::from_chars(file_string, file_string_end, buffer.z).ptr;
    file_string++;
    vcoords.push_back(std::move(buffer));
}
//...
//...
while (file_string = strstr(file_string, "v ")) {
    size++;
    file_string++;
}
vcoords.reserve(size);
//...

对于这类数据

(...)
v 1.000000 1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 -1.000000
(...)

它们可以工作,而且工作速度足够快。它们还会生成警告,例如:

C26481:不要使用指针运算。

C26486:不要将可能无效的指针传递给函数。对“strstr”的调用中的参数 0“file_string”可能无效(lifetime.3)。

如何将 strstr/指针算术组合替换为能够相对快速完成其工作且不会生成此类警告的东西?我尝试解决与 std::string-to-float 转换相关的类似问题,但他们要么使用了 std::stringstream,这是非常慢,或者假设所讨论的字符串只包含一个值。

最佳答案

在启用核心指南检查器后针对更改进行了编辑

我试用了 std::from_chars。有趣的事实:它不适用于浮点值的 gcc 或 clang!那...可能保证在功能成熟之前不要使用它。

让指南检查器闭嘴的事情:

  • gsl::at 是指针运算的秘籍。没有警告
  • 生命周期检查器有点笨。它不知道由 string_view 包裹的 sting 文字仍然具有无限生命周期,但如果您使用字符串 View 文字 (""sv),它不会标记。
  • 仍然使用string::find进行搜索,然后将位置添加到string::data()
  • 我之前建议使用索引而不是指针运算,但分析也不喜欢那样。
using namespace std::literals;
const std::string file_string = "\n"
    "v 1.000000 1.000000 -1.000000\n"
    "v 1.000000 -1.000000 -1.000000\n"
    "v 1.000000 1.000000 1.000000\n";
const auto tag = "v "sv;
const char* file_string_end = &gsl::at(file_string, file_string.size());

std::vector<vec::vec3<float>> vcoords;
std::string::size_type pos = 0;
while ((pos = file_string.find(tag, pos)) != std::string::npos) {
    vec::vec3<float> buffer = { 0.0f };
    auto [x_ptr, x_ec] = std::from_chars(
        &gsl::at(file_string, pos + tag.size()), 
        file_string_end, 
        buffer.x);
    if (x_ec != std::errc()) {
        throw std::runtime_error("bad x");
    }
    std::string_view x_view(x_ptr);
    auto [y_ptr, y_ec] = std::from_chars(
        &gsl::at(x_view, 1), 
        file_string_end, 
        buffer.y);
    if (y_ec != std::errc()) {
        throw std::runtime_error("bad y");
    }
    std::string_view y_view(y_ptr);
    auto [z_ptr, z_ec] = std::from_chars(
        &gsl::at(y_view, 1), 
        file_string_end, 
        buffer.z);
    if (z_ec != std::errc()) {
        throw std::runtime_error("bad z");
    }
    vcoords.push_back(buffer);
}

https://godbolt.org/z/F9j7FA

关于c++ - 如何用符合 C++ 核心准则的代码替换 C 风格的字符串解析?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58793836/

相关文章:

c++ - 启动停止守护进程不发送 SIGTERM

parsing - 在 Haskell 中正确使用 ReadP

php - php中的json解析响应

ios - 使用附加元数据将 Wavefront 文件转换为 .ifc

长度为100的C++循环队列类

c++ - Qt 服务器客户端代码

python - 从 pandas 数据框创建单个 XML 文件

three.js - Wavefront 的 OBJ 和 MTL 的 MIME 类型

c++ - 带有 tinyobjloader 的 OpenGL 顶点数组对象

c++ - boost circular_buffer 或堆排序性能