假设我有一个字符串,我想生成一个包含原始字符串且反向连接的新字符串。
以下是否可以保证有效?
auto pq = [](std::string &s){
s.reserve(2*s.size());
s.append(s.rbegin(), s.rend());
};
我看到reserve
应该恰当地设置capacity
。但是,对反向迭代器应用append
会导致那些迭代器失效吗?
我的C ++。11版(与C++.17 draft语言相同),§[string.capacity]
void reserve(size_type res_arg=0);
- 成员函数
reserve()
是一个指令,用于通知basic_string
对象计划的更改 大小,以便它可以相应地管理存储分配。- 效果:在
reserve()
之后,capacity()
大于或等于保留的参数。 [注意:致电reserve()
参数小于res_arg
的{{1}}实际上是非绑定收缩请求。 使用capacity()
的呼叫实际上是一种非绑定的缩小到适合请求。 - 结束记录]- 抛出: length_error if
醇>res_arg <= size()
。 227227) reserve()使用 allocator_traits :: allocate(),它可能抛出适当的异常。
虽然,§[string.append]说
res_arg > max_size()
basic_string&
- 要求:
append(const charT* s, size_type n);
指向至少s
n
元素的数组。- 投掷:
charT
iflength_error
。- 效果:该函数将
size() + n > max_size()
控制的字符串替换为长度为*this
的字符串 其第一个size() + n
元素是由size()
控制的原始字符串的副本,其余为 元素是*this
的初始n
元素的副本。- 返回:
醇>s
。
答案 0 :(得分:6)
这不是你实际调用的std::string::append
的重载。你打电话的是template<class InputIterator> basic_string& append(InputIterator first, InputIterator last);
。在那里,标准说([string.append]/21)它相当于在追加之前构造一个新字符串:
效果:相当于
append(basic_string(first, last, get_allocator()))
。
请注意,在这里,构造函数调用basic_string(first, last, get_allocator())
在调用append
的不同重载之前创建一个临时字符串,因此无论重新分配在另一个{ {1}}无关紧要。这意味着,即使没有先调用append
,这也应该是安全的。
请注意,无法保证字符串以这种方式实现;标准说&#34;等同于&#34;,而不是&#34;实施为&#34;。实现可以做任何具有相同结果的事情,但在这种情况下&#34;相同的结果&#34;意味着它仍然需要使用从调用它的相同字符串派生的迭代器。
答案 1 :(得分:1)
修改强>
我不相信这个答案是正确的,请参阅评论。但为了保留有价值的评论,我将在那里留下答案。
最直接的追加看起来像是:
template<class T>
void string::append(T begin, T end) {
reserve(size() + std::distance(end, begin));
while (; begin != end; ++begin) {
*this += *begin;
}
}
由于在保留之后迭代器不应该无效,因此在整个函数期间,begin仍然对解除引用和递增有效。
在上面的示例中,reserve
保证从我有权访问的最新草稿(http://eel.is/c++draft/string.capacity)中删除操作:
(24.3.2.4)void reserve(size_type res_arg);
#Effects:一个指令,用于通知basic_string计划的大小变化,以便相应地管理存储分配。 在reserve()之后,capacity()大于或等于参数 如果重新分配发生,则保留;并等于之前的值 容量()否则。此时重新分配会发生 如果当前容量小于reserve()的参数