std::string::reserve() and std::string::clear() conundrum
std::string::reserve() and std::string::clear() conundrum
这个问题从一些代码开始,只是因为我认为更容易看到我所追求的东西:
/*static*/
void
Url::Split
(std::list<std::string> & url
, const std::string& stringUrl
)
{
std::string collector;
collector.reserve(stringUrl.length());
for (auto c : stringUrl)
{
if (PathSeparator == c)
{
url.push_back(collector);
collector.clear(); // Sabotages my optimization with reserve() above!
}
else
{
collector.push_back(c);
}
}
url.push_back(collector);
}
在上面的代码中,collector.reserve(stringUrl.length());
行应该减少在下面的循环中执行的堆操作量。毕竟,每个子字符串不能超过整个 url,因此像我一样保留足够的容量看起来是个好主意。
但是,一旦子字符串完成并将其添加到 url 零件列表中,我需要以一种或另一种方式将字符串重置为长度 0。简短的"窥视定义"检查向我表明,至少在我的平台上,保留的缓冲区将被释放,因此,我的 reserve(( 调用的目的受到损害。
在内部,如果清楚,它会调用一些_Eos(0)
。
我也可以用collector.resize(0)
完成相同的任务,但偷看定义显示它也在内部调用_Eos(newsize)
,因此行为与调用clear()
的情况相同。
现在的问题是,是否有一种便携式方法来建立预期的优化,以及哪个std::string
功能可以帮助我。
当然,我可以写collector[0] = ' ';
但这对我来说看起来很不对劲。
旁注:虽然我发现了类似的问题,但我不认为这是其中任何一个的重复。
谢谢,提前。
在 C++11 标准中,clear
是根据 erase
定义的,这被定义为值替换。没有明显的保证缓冲区未解除分配。它可能在那里,隐含在其他东西中,但我没有找到任何这样的。
如果没有正式保证clear
不会解除分配,并且似乎至少从 C++11 开始它不存在,您有以下选择:
-
忽略问题。
毕竟,动态缓冲区分配产生的微秒数很可能是绝对无关紧要的,此外,即使没有正式的保证,clear
释放的可能性也非常低。 -
需要
clear
不解除分配的C++实现。
(您可以为此效果添加assert
,选中.capacity()
。 -
执行自己的缓冲区实现。
忽略问题似乎是安全的,即使分配(如果执行(在时间紧迫的情况下也是如此,因为对于常见的实现clear
不会减少容量。
例如,这里以 g++ 和 Visual C++ 为例:
#include <iostream>
#include <string>
using namespace std;
auto main() -> int
{
string s = "Blah blah blah";
cout << s.capacity();
s.clear();
cout << ' ' << s.capacity() << endl;
}
C:\my\so\0284>g++ keep_capacity.cpp -std=c++11C:\my\so\0284>a14 14C:\my\so\0284>cl keep_capacity.cpp/二月keep_capacity.cppC:\my\so\0284>b15 15C:\my\so\0284>_
如果您真的想走那么远,可以按以下步骤进行自己的缓冲区管理:
#include <iostream>
#include <string>
#include <vector>
namespace my {
using std::string;
using std::vector;
class Collector
{
private:
vector<char> buffer_;
int size_;
public:
auto str() const
-> string
{ return string( buffer_.begin(), buffer_.begin() + size_ ); }
auto size() const -> int { return size_; }
void append( const char c )
{
if( size_ < int( buffer_.size() ) )
{
buffer_[size_++] = c;
}
else
{
buffer_.push_back( c );
buffer_.resize( buffer_.capacity() );
++size_;
}
}
void clear() { size_ = 0; }
explicit Collector( const int initial_capacity = 0 )
: buffer_( initial_capacity )
, size_( 0 )
{ buffer_.resize( buffer_.capacity() ); }
};
auto split( const string& url, const char pathSeparator = '/' )
-> vector<string>
{
vector<string> result;
Collector collector( url.length() );
for( const auto c : url )
{
if( pathSeparator == c )
{
result.push_back( collector.str() );
collector.clear();
}
else
{
collector.append( c );
}
}
if( collector.size() > 0 ) { result.push_back( collector.str() ); }
return result;
}
} // namespace my
auto main() -> int
{
using namespace std;
auto const url = "http://en.wikipedia.org/wiki/Uniform_resource_locator";
for( string const& part : my::split( url ) )
{
cout << '[' << part << ']' << endl;
}
}
- cppcheck在const std::string[]上引发警告
- 将std::string传递给WriteConsole API
- 为std::string的某个索引赋值
- 使用 std::string () const 函数启动线程或未来
- 当我们进行一些操作时,应该使用什么'std::string'或'std::stringstream'?
- 如何更改大小(std::string)
- std::string 的对象真的可以移动吗?
- SegFault 同时使用 std::string::operator+= 和函数作为参数
- 无法从 std::string 中提取C++ Unicode 符号
- std::string 构造函数如何处理固定大小的 char[]?
- 真的没有来自 std::string_view 的 std::string 的显式构造函数吗?
- 将C++ std::string 转换为 UTF-16-LE 编码的字符串
- 重载 + 自己的类和 std::string 的运算符
- 如何使用 std::string 作为 QHash 的键?
- 将日语 wstring 转换为 std::string
- 可以从std::string继承以提供类型一致性吗
- 构造函数采用std::string_view与std::string并移动
- 在共享缓冲区内存中创建 ::std::string 对象
- std::string.size() 未知行为
- Valgrind 在 std::string::swap 中报告 SIGILL