std :: string :: reserve()和std :: string :: clear()难题

时间:2015-05-28 23:37:06

标签: c++ string c++11

这个问题从一些代码开始,只是因为我认为更容易看到我的目标:

/*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';,但这对我来说非常不合适。

旁注:虽然我发现了类似的问题,但我不认为这是任何问题的重复。

提前谢谢。

1 个答案:

答案 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";