我正在尝试使用
size_type
作为 std::copy()
算法中字符串迭代器的偏移量。当 size_type
为 std::string::npos
时,GCC/Clang 不会抛出任何异常,但 MSCV 会抛出 cannot seek string iterator before begin
。
为什么MSCV会抛出这个异常?在这种情况下哪个编译器是正确的?
我已经在编译器资源管理器上使用以下编译器测试了该程序:
海湾合作委员会 -
x86-64 gcc 14.2
x86-64 clang 19.1.0
x86 msvc v19.latest
这是一个最小的可重现程序
#include <iostream>
#include <algorithm>
#include <iterator>
#include <cstdint>
#include <string>
// timestamp in hhmmss.zzz format; can be in hhmmss format also
void test(const std::string& timestamp)
{
std::string timeWithoutMs{};
std::int32_t milliseconds{};
auto itr = timestamp.find(".");
if( itr != std::string::npos)
{
milliseconds = std::stoi( timestamp.substr(itr + 1, timestamp.length() - itr));
}
std::copy( timestamp.begin(), timestamp.begin() + itr, std::back_inserter(timeWithoutMs));
std::cout << timeWithoutMs << " - " << milliseconds << std::endl;
}
int main()
{
test("135523.495");
test("135523"); // MSVC throws exception here
}
std::string::npos
的定义是-1
。因此,当 itr
为 std::string::npos
时,std::copy
调用如下所示:
std::copy( timestamp.begin(), timestamp.begin() + -1, std::back_inserter(timeWithoutMs));
请注意,在第二个参数中,您尝试递减字符串的开始迭代器。 MSVC 的标准库选择对此进行诊断,因为默认情况下它具有“检查迭代器”,这确保迭代器在范围内。 GCC 和 Clang 不需要对此进行诊断,因此它们的行为仍然正确,但您的程序无效,因为您尝试使用无效的迭代器范围调用
std::copy
。
您可以改用
std::string::substr
,当 count
参数为 std::string::npos
时,这是明确定义的:
timeWithoutMs = timestamp.substr(0, itr);
我还将
itr
变量重命名为 idx
,因为 std::string::find
返回索引而不是迭代器,我认为这会增加您的困惑。