这个问题从一些代码开始,只是因为我认为更容易看到我的目标:
/*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部件列表中,我需要将字符串重置为长度为0的方式。简短的定义&#34;检查告诉我,至少在我的平台上,保留缓冲区将被释放,因此,我的reserve()调用的目的会受到影响。
在内部,如果有明确的话,它会调用一些_Eos(0)
。
我也可以使用collector.resize(0)
完成同样的操作,但是偷看定义会发现它在内部调用_Eos(newsize)
,因此行为与调用clear()
时的行为相同。
现在的问题是,如果有可移植方式来建立预期的优化,哪个std::string
函数可以帮助我。
当然我可以写collector[0] = '\0';
,但这对我来说非常不合适。
旁注:虽然我发现了类似的问题,但我不认为这是任何问题的重复。
提前谢谢。
答案 0 :(得分:4)
在C ++ 11标准中,clear
是根据erase
定义的,clear
被定义为值替换。没有明显的保证缓冲区没有被释放。它可能存在,隐含在其他东西中,但我找不到任何这样的东西。
如果没有正式保证clear
没有解除分配,并且看起来至少从C ++ 11开始就不存在,那么您有以下选择:
忽略此问题
毕竟,动态缓冲区分配所产生的微秒几乎是无关紧要的,此外,即使没有正式的保证,clear
解除分配的可能性也非常低。
要求在assert
未解除分配的情况下执行C ++
(您可以在此效果中添加.capacity()
,然后选中clear
。)
执行自己的缓冲区实现。
即使分配(如果执行)对时间至关重要,忽略问题似乎也是安全的,因为具有常见实现#include <iostream>
#include <string>
using namespace std;
auto main() -> int
{
string s = "Blah blah blah";
cout << s.capacity();
s.clear();
cout << ' ' << s.capacity() << endl;
}
的不会降低容量。
例如,这里以g ++和Visual C ++为例:
#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;
}
}
C:\my\so\0284>g++ keep_capacity.cpp -std=c++11 C:\my\so\0284>a 14 14 C:\my\so\0284>cl keep_capacity.cpp /Feb keep_capacity.cpp C:\my\so\0284>b 15 15 C:\my\so\0284>_
进行自己的缓冲区管理,如果你真的想要那么做,可以按如下方式进行:
$counter = 0;
// Check if the parameter 'c' as passed and its an numeric
if (!empty($_GET["c"]) && is_numeric($_GET["c"]))
$counter = $_GET["c"];
$action = isset($_GET["action"]) ? $_GET["action"] : null;
if ($action == null)
die("invalid action");
switch ($action)
{
case "add":
{
$counter++;
break;
}
case "remove":
{
// Decrease only when its greater then 0
if ($counter > 0)
$counter--;
break;
}
default:
{
die("You can only 'add' or 'remove'");
break;
}
}
echo "You clicked " . $counter . " times";