std::string references、std::regex和boost::filesystem的基本概念
Basic concepts with std::string references, std::regex and boost::filesystem
下面,我生成了损坏的代码和相同的固定版本。问题是我无法完全向自己解释为什么前者不起作用,而后者却有效。我显然需要回顾C++语言的一些非常基本的概念:您能否提供关于我应该审查的内容的指示,并可能还解释为什么我得到损坏代码的结果。
在"..代码中引用的/docs/' 目录,我只是在 linux 上使用 'touch' 命令创建了多个 doc......各种长度的 HTML 文件。
#include <iostream>
#include <regex>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
int main() {
fs::path p("../docs/");
for (auto& dir_it : fs::directory_iterator(p)) {
std::regex re = std::regex("^(doc[a-z]+)\.html$");
std::smatch matches;
// BROKEN HERE:
if (std::regex_match(dir_it.path().filename().string(), matches, re)) {
std::cout << "tt" <<dir_it.path().filename().string();
std::cout << "ttt" << matches[1] << std::endl;
}
}
return 0;
}
生产:
documentati.html ati
documentationt.html �}:ationt
document.html document
documenta.html documenta
docume.html docume
documentat.html documentat
docum.html docum
documentatio.html ��:atio
documen.html documen
docu.html docu
documentation.html ��:ation
documaeuaoeu.html ��:aoeu
注意1:上述错误是由超过一定长度的文件名触发的。我只明白这是因为 std::string 对象正在调整自身大小。
注意 2:上面的代码与以下问题中使用的代码非常相似,但使用 boost::regex_match 而不是 std::regex_match: 我可以使用掩码在带有 Boost 的目录中迭代文件吗?
它以前也为我工作,但现在我使用 GCC 5.4 而不是 GCC 4.6,std::regex而不是 boost::regex、C++11 和更新版本的 boost::filesystem。哪个更改是相关的,导致工作代码被破坏?
固定:
#include <iostream>
#include <regex>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
int main() {
fs::path p("../docs/");
for (auto& dir_it : fs::directory_iterator(p)) {
std::regex re = std::regex("^(doc[a-z]+)\.html$");
std::smatch matches;
std::string p = dir_it.path().filename().string();
if (std::regex_match(p, matches, re)) {
std::cout << "tt" <<dir_it.path().filename().string();
std::cout << "ttt" << matches[1] << std::endl;
}
}
return 0;
}
生产:
documentati.html documentati
documentationt.html documentationt
document.html document
documenta.html documenta
docume.html docume
documentat.html documentat
docum.html docum
documentatio.html documentatio
documen.html documen
docu.html docu
documentation.html documentation
documaeuaoeu.html documaeuaoeu
使用 boost 1.62.0-r1 和 gcc (Gentoo 5.4.0-r3(,boost::filesystem 文档似乎没有提供任何关于 path((.filename((.string(( 返回的明确指示:
http://www.boost.org/doc/libs/1_62_0/libs/filesystem/doc/reference.html#path-filename 它似乎取决于:
为什么boost::filesystem::p ath::string((在Windows上按值返回,在POSIX上按引用返回?
std::smatch
不会将构成匹配项的字符的副本存储,而只会将迭代器对存储到搜索的原始字符串中。
第一个片段将临时字符串传递给std::regex_match
。当你开始检查matches
时,那个字符串已经消失了,matches
持有的迭代器都晃来晃去。然后,程序通过尝试使用它们来展示未定义的行为。
在第二个片段中,传递给std::regex_match
的字符串在使用时仍然有效matches
所以一切都很好。
注意 1:根据文件名长度,问题的表现不同可能是由于小字符串优化。std::string
实现通常会在类实例中保留一个小缓冲区,并在那里存储短字符串;而较长的字符串在堆上分配。以前由临时字符串占用的堆栈空间可能仍然完好无损,而堆空间已重新用于其他分配。无论哪种方式,程序都表现出未定义的行为 - "似乎有效"是 UB 的一种可能表现。
注 2:path::string()
按值返回还是按引用返回并不重要。path::filename()
按值返回,因此无论哪种方式dir_it.path().filename().string()
都会过早地被销毁,无论是临时dir_it.path().filename()
对象的成员,还是由string()
动态制造。
- 带有特殊路径部分的"std::filesystem::weakly_canonical"失败
- std::filesystem::copy throws filesystem_error
- 在带有尾部斜杠的路径上返回 std::filesystem::create_directories() 的值
- std::filesystem 和 std::experimental::filesystem 之间的路径差异
- 如何将 std::filesystem::p ath 转换为 LPCSTR,以便在 LoadLibrary() 变体之一
- 不能将C++的"std::filesystem"库与介子构建一起使用
- Visual Studio 2019 C++ and std::filesystem
- 'std::filesystem::d irectory_iterator' 编译器问题
- std::filesystem::create_directories Visual Studio 2017
- 如何获取 std::filesystem::p ath 中的最后一个目录?
- 为什么目录中的 std::filesystem::file_size 留给实现?
- 如何在 C++17 中检索 std::filesystem::file_time_type 的时钟类型
- std::filesystem::directory_迭代器链接器问题(C++17)
- 'std::filesystem::p ath' 没有标准哈希吗?
- [LLVM-9 clang-9 OSX]: std::filesystem::path unrecognized
- std::filesystem::p ath 和 std::string 之间的隐式转换,应该发生吗?
- 如何使用GCC 9将`std :: filesystem :: file_time_type`转换为字符串
- 从std :: fileSystem ::路径对象的类中退出时的分割故障
- 使用std :: filesystem :: path中的double
- c++ std::bad_alloc on std::filesystem::path append