std::basic_string<CharT,Traits,Allocator>::resize_and_overwrite
来自cppreference.com
<tbody>
</tbody>
template< class Operation > constexpr void resize_and_overwrite( size_type count, Operation op ); |
(C++23 起) | |
重设字符串大小以含有至多 count 个字符,用用户提供的操作 op 修改可能不确定的内容并设置长度。这样就避免了初始化大小合适的 std::string 时所产生的成本,当它打算作为要被填充的字符数组时,例如,C API 调用。
此函数执行下列步骤:
- 获得至少含有
count + 1个字符的存储,并使它的前k个字符等于*this的前k个字符,其中k是count与调用resize_and_overwrite前size()的结果的较小者。令p代表指向该存储中首个字符的指针。- 相等性以如同检查
this->compare(0, k, p, k) == 0确定。 [p + k,p + count]中的字符可能拥有不确定值。
- 相等性以如同检查
- 求值
std::move(op)(p, count),令它的返回值为r。 - 以
[p,p + r)替换*this的内容(这会设置*this的长度为r)。使所有指向范围[p,p + count]中的指针与引用失效。
如果 r 不具有整数式类型,那么程序非良构。
如果满足以下任意条件,那么行为未定义:
std::move(op)(p, count)抛出异常。std::move(op)(p, count)修改p或count。r不在范围[0,count]中。- 范围
[p,p + r)中的任何字符拥有不确定值。
推荐实现避免不必要的复制与分配,例如通过使得 p 等于指向调用后为 *this 分配的字符存储的起始指针,如果 count 小于或等于 capacity(),那么该存储能等同于 *this 的既存存储。
参数
| count | - | 字符串的最大可能的新大小 |
| op | - | 用于设置字符串新内容的函数对象 |
异常
如果 count > max_size(),那么就会抛出 std::length_error。
对应的 Allocator 所抛的任何异常。
如果从 std::move(op)(p, count) 抛出异常,那么行为未定义。否则抛出异常的情况下此函数无效果。
注解
无论重分配是否出现,resize_and_overwrite 都使所有指向 *this 中的迭代器、指针及引用失效。实现可以假设调用 resize_and_overwrite 后字符串的内容不会被别名化。
| 功能特性测试宏 | 值 | 标准 | 功能特性 |
|---|---|---|---|
__cpp_lib_string_resize_and_overwrite |
202110L |
(C++23) | std::basic_string::resize_and_overwrite
|
示例
测试这个示例的链接:compiler explorer。
运行此代码
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <string>
#include <string_view>
static_assert(__cpp_lib_string_resize_and_overwrite);
constexpr std::string_view fruits[]{"apple", "banana", "coconut", "date", "elderberry"};
int main()
{
// 简单情况下,仅后附 fruits[0]。字符串大小会增长。
std::string s{"Food: "};
s.resize_and_overwrite(16, [sz = s.size()](char* buf, std::size_t buf_size) noexcept
{
const auto to_copy = std::min(buf_size - sz, fruits[0].size());
std::memcpy(buf + sz, fruits[0].data(), to_copy);
return sz + to_copy;
});
std::cout << "1. " << std::quoted(s) << '\n';
// 缩减大小的情况。注意,总是调用用户的 lambda 表达式。
s.resize_and_overwrite(10, [](char* buf, int n) noexcept
{
return std::find(buf, buf + n, ':') - buf;
});
std::cout << "2. " << std::quoted(s) << '\n';
std::cout << "3. 复制数据直至缓冲区满。打印数据和大小。\n";
std::string food{"Food:"};
const auto resize_to{27};
std::cout << "起初,food.size: " << food.size()
<< ", food.capacity: " << food.capacity()
<< ", resize_to: " << resize_to
<< ", food: " << std::quoted(food) << '\n';
food.resize_and_overwrite
(
resize_to,
[food_size = food.size()](char* p, std::size_t n) noexcept -> std::size_t
{
// p[0]..p[n] 为可赋值范围
// p[0]..p[min(n, food_size) - 1] 为可读取范围
// (其内容起初等于原字符串)
// 调试打印:
std::cout << "Operation() 内; n: " << n << '\n';
// 在空间足够时,把水果复制到缓冲区 p 中。
char* first = p + food_size;
for (char* const end = p + n; const std::string_view fruit : fruits)
{
char* last = first + fruit.size() + 1;
if (last > end)
break;
*first++ = ' ';
std::ranges::copy(fruit, first);
first = last;
}
const auto final_size{static_cast<std::size_t>(first - p)};
// 调试打印:
std::cout << "Operation() 内; final_size: " << final_size << '\n';
assert(final_size <= n);
return final_size; // 返回值为字符串的实际新长度,必定在范围 0..n 中
}
);
std::cout << "最后, food.size: " << food.size()
<< ", food.capacity: " << food.capacity()
<< ", food: " << std::quoted(food) << '\n';
}
可能的输出:
1. "Food: apple"
2. "Food"
3. 复制数据直至缓冲区满。打印数据和大小。
起初, food.size: 5, food.capacity: 15, resize_to: 27, food: "Food:"
Operation() 中; n: 27
Operation() 中; final_size: 26
最后, food.size: 26, food.capacity: 30, food: "Food: apple banana coconut"
参阅
| 更改存储的字符数 (公开成员函数) |