为什么VS2008 std :: string.erase()移动它的缓冲区?
我想逐行阅读一个文件并捕获一个特定的输入行。 为了获得最大性能,我可以通过读取整个文件并使用指针迭代其内容来实现此目的,但此代码不是性能关键,因此我希望使用更具可读性和类型安全性的std库样式实现。
所以我拥有的是这样的:
std::string line;
line.reserve(1024);
std::ifstream file(filePath);
while(file)
{
std::getline(file, line);
if(line.substr(0, 8) == "Whatever")
{
// Do something ...
}
}
虽然这不是性能关键的代码,但在解析操作之前我已经调用了line.reserve(1024),以便在读入更大的行时排除多次重新分配字符串。
在std :: getline内部,在将每行的字符添加到字符串之前,字符串会被擦除。 我通过这段代码让自己满意,记忆没有被重新分配每次迭代,我发现我的脑子炸了。
深入字符串::擦除,而不是只是将其大小变量重置为零,它实际上正在做的是用指针值调用memmove_s,这些指针值会覆盖缓冲区的未使用部分并随后使用缓冲区中未使用的部分,除了memmove_s正在用零计数参数调用,即请求移动零字节。
问题:
为什么我会在我可爱的循环中间需要库函数调用的开销,尤其是那些被称为什么也不做的循环?
我自己还没有选择它,但是在什么情况下,这个电话实际上不会做什么,而是实际上开始移动大块缓冲区?
为什么它这样做呢?
奖金问题:什么是C ++标准库标签?
这是我一年前报告的一个已知问题,要利用您必须升级到未来版本编译器的修复程序。
Connect Bug:“ std::string::erase
在擦除到最后时会很慢,这会影响std::string::resize
”
该标准没有提到任何关于std::string
函数的复杂性,除了swap
。
std::string::clear()
是根据std::string::erase()
,而std::string::erase()
必须移动被擦除块之后的所有字符。 那么,为什么它不能称之为标准功能呢? 如果你有一些profiler输出证明这是一个瓶颈,那么也许你可以抱怨它,但坦率地说,我看不出它有什么不同。 (避免呼叫的必要逻辑最终可能比呼叫花费更多。)
此外,在使用它们之前,您并未检查调用getline
的结果。 你的循环应该是这样的:
while ( std::getline( file, line ) ) {
// ...
}
如果你担心性能,为了做比较而创建一个子字符串(一个新的std::string
)比调用memmove_s
要昂贵得多。 有什么问题,如:
static std::string const target( "Whatever" );
if ( line.size() >= target.size()
&& std::equal( target.begin(), target().end(), line.being() ) ) {
// ...
}
我认为这是决定字符串是否以特定值开始的最习惯的方式。
(我可以从经验中补充一点,这里的reserve
也不会给你买多少,在你阅读了文件中的几行文字之后,你的字符串反正不会增长太多,所以会很少第一个几行之后重新分配。另一个过早优化的情况?)
在这种情况下,我认为你提到的阅读整个文件并迭代结果的想法实际上可能会给出简单的代码。 您只需更改:“读取行,检查前缀,进程”为“读取文件,扫描前缀和进程”:
size_t not_found = std::string::npos;
std::istringstream buffer;
buffer << file.rdbuf();
std::string &data = buffer.str();
char const target[] = "nWhatever";
size_t len = sizeof(target)-1;
for (size_t pos=0; not_found!=(pos=data.find(target, pos)); pos+=len)
{
// process relevant line starting at contents[pos+1]
}
链接地址: http://www.djcxy.com/p/91705.html
上一篇: Why does the VS2008 std::string.erase() move its buffer?