Namespaces
Variants

std::basic_string<CharT,Traits,Allocator>:: resize_and_overwrite

From cppreference.net
std::basic_string
template < class Operation >
constexpr void resize_and_overwrite ( size_type count, Operation op ) ;
(自 C++23 起)

将字符串大小调整为最多包含 count 个字符,使用用户提供的操作 op 来修改可能未初始化的内容并设置长度。这避免了在需要将字符串用作字符数组(例如被C API调用填充)时,初始化适当大小的 std::string 所带来的开销。

此函数执行以下步骤:

  1. 获取包含 count + 1 个字符的连续存储空间,并使其前 k 个字符等于 * this 的前 k 个字符,其中 k count 与调用 resize_and_overwrite size ( ) 结果的较小值。令 p 表示指向存储空间中首字符的指针。
    • 相等性判定相当于检查 this - > compare ( 0 , k, p, k ) == 0
    • 区间 [ p + k , p + count ] 内的字符可能具有不确定值。
  2. 执行 std :: move ( op ) ( p, count ) ,令 r 为返回值。
  3. * this 的内容替换为 [ p , p + r ) (这将把 * 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 << "In 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 << "In Operation(); final_size: " << final_size << '\n';
            assert(final_size <= n);
            return final_size; // 返回值是字符串的实际新长度
                               // 必须在 0..n 范围内
        }
    );
    std::cout << "最终状态,food.size: " << food.size()
              << ", food.capacity: " <<</

参见

更改存储的字符数量
(公开成员函数)