c++ - 如何用符合 C++ 核心准则的代码替换 C 样式的字符串解析?
问题描述
以这两个代码片段为例:
//...
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: Don't use pointer arithmetic.
C26486: Don't pass a pointer that may be invalid to a function. Parameter 0 'file_string' in call to 'strstr' may be invalid (lifetime.3).
如何将 strstr/pointer 算术组合替换为可以相当快地完成其工作并且不会产生此类警告的东西?我尝试解决与std::string
-to-float
转换相关的类似问题,但他们要么使用了std::stringstream
,这非常慢,要么假设所讨论的字符串只包含一个值。
解决方案
启用核心指南检查器后编辑更改
我在使用std::from_chars
. 有趣的事实:它还不适用于 gcc 或 clang 的浮点值!那......可能保证在功能成熟之前不要使用它。
关闭指南检查器的事情:
gsl::at
是指针算术的作弊码。没有警告- 寿命检查器有点愚蠢。它不知道被 a 包裹的字符串文字
string_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);
}
推荐阅读
- delphi - Delphi 将文件从 Windows 资源管理器拖放到 TListView 不起作用
- php - 从 Phalcon 模型中获取 PHP 中 DateTime 列的 DateTime 对象
- javascript - 阻止打印预览对话框并直接打印元素
- macos-mojave - (MacOS Mojave 10.14.6) - 为什么 /usr/local 中的“lib”是 Unix 可执行文件而不是文件夹?
- javascript - Slidetoggle() 功能无法正常工作
- java - 这个 Activity 已经有一个由窗口装饰提供的操作栏。更新 android studio 后
- r - 如何删除 2 组的一些 NA
- python - Python 多处理 - Pool.map 的结果为无
- java - 在输入中使用空格时 Java 扫描器输入不匹配
- android - 从使用导航组件的片段返回时会触发哪些方法?