我有一个来自ostringstream
的字符串。我目前正在尝试替换此字符串中的一些字符(content.replace(content.begin(), content.end(), "\n", "");
),但有时我会遇到异常:
malloc: *** mach_vm_map(size=4294955008) failed (error code=3)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
std::bad_alloc
我怀疑这是因为字符串太大了。这些情况的最佳做法是什么?在堆上声明字符串?
更新
我的完整方法:
xml_node HTMLDocument::content() const {
xml_node html = this->doc.first_child();
xml_node body = html.child("body");
xml_node section = body.child("section");
std::ostringstream oss;
if (section.type() != xml_node_type::node_null) {
section.print(oss);
} else {
body.print(oss);
}
string content;
content = oss.str();
content.replace(content.begin(), content.end(), "<section />", "<section></section>");
content.replace(content.begin(), content.end(), "\t", "");
xml_node node;
return node;
}
答案 0 :(得分:1)
没有std::string::replace
成员函数的重载接受一对迭代器,一个const char*
要搜索,const char*
用作替换,这就是你的问题所在从:
content.replace(content.begin(), content.end(), "\n", "");
匹配以下重载:
template <class InputIterator>
string& replace(iterator i1, iterator i2,
InputIterator first, InputIterator last);
即,"\n"
和""
被视为范围<first; last)
,这取决于他们拥有的地址,是否会导致程序崩溃。
您必须使用std::regex
或实现您自己的迭代std::string
的逻辑,并用替换字符串替换任何遇到的模式。
答案 1 :(得分:1)
行:
content.replace(content.begin(), content.end(), "<section />", "<section></section>");
content.replace(content.begin(), content.end(), "\t", "");
导致未定义的行为。它们匹配功能:
template<class InputIterator>
std::string& std::string::replace(
const_iterator i1, const_iterator i2,
InputIterator j1, InputIterator j2);
InputIterator
解析为char const*
。问题是
两个迭代器之间的距离,以及是否
第二个可以从第一个到达,是未定义的,因为它们
指向完全不相关的内存。
从你的代码中,我认为你不明白什么
std::string::replace
。它取代了[i1,i2)
中的范围
包含由范围[j1,j2)
定义的文本的字符串。它
不进行任何搜索和比较;它是在之后使用
你找到了需要更换的范围。主叫:
content.replace(content.begin(), content.end(), "<section />", "<section></section>");
具有与以下完全相同的效果:
content = std::string( "<section />", "<section></section>");
,肯定不你想要的东西。
在C ++ 11中,有一个regex_replace
函数可能是
一些用途,虽然如果你真的这么做非常大
字符串,它可能不是最高性能(添加
正则表达式的灵活性是有代价的); ID
可能使用类似的东西:
std::string
searchAndReplace(
std::string const& original,
std::string const& from,
std::string const& to)
{
std::string results;
std::string::const_iterator current = original.begin();
std::string::const_iterator end = original.end();
std::string::const_iterator next = std::search( current, end, from.begin(), from.end() );
while ( next != end ) {
results.append( current, next );
results.append( to );
current = next + from.size();
next = std::search( current, end, from.begin(), from.end() );
}
results.append( current, next );
return results;
}
对于非常大的字符串,一些用于猜测大小的启发式,
然后在reserve
上执行results
可能是一个好主意
同样。
最后,由于你的第二行只删除'\t'
,你就是了
最好使用std::remove
:
content.erase( std::remove( content.begin(), content.end(), '\t' ), content.end() );
答案 2 :(得分:0)
AFAIK stl字符串总是在堆上分配,如果它们超过某个(小)大小,例如32 chars in Visual Studio
如果获得分配例外,您可以做什么:
错误的分配可能并不意味着你的内存不足,更有可能是你的连续内存不足。绳索类可能更适合您,因为它在内部分配了字符串。
答案 3 :(得分:0)
这是从字符串中删除字符的正确(且合理有效)方法之一,如果您想要复制并保留原始字符:
#include <algorithm>
#include <string>
std::string delete_char(std::string src, char to_remove)
{
// note: src is a copy so we can mutate it
// move all offending characters to the end and get the iterator to last good char + 1
auto begin_junk = std::remove_if(src.begin(),
src.end(),
[&to_remove](const char c) { return c == to_remove; });
// chop off all the characters we wanted to remove
src.erase(begin_junk,
src.end());
// move the string back to the caller's result
return std::move(src);
}
这样叫:
std::string src("a\nb\bc");
auto dest = delete_char(src, '\n');
assert(dest == "abc");
如果您希望修改字符串,则只需:
src.erase(std::remove_if(src.begin(), src.end(), [](char c) { return c == '\n'; }), src.end());