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

来自cppreference.com
< cpp‎ | string‎ | basic string
 
 
 
std::basic_string
成员函数
元素访问
迭代器
容量
操作
basic_string::resize_and_overwrite
(C++23)  
搜索
常量
推导指引 (C++17)
非成员函数
I/O
比较
(C++20 前)(C++20 前)(C++20 前)(C++20 前)(C++20 前)(C++20)
数值转换
(C++11)(C++11)(C++11)
(C++11)(C++11)    
(C++11)(C++11)(C++11)
(C++11)
(C++11)
辅助类
 
template< class Operation >
constexpr void resize_and_overwrite( size_type count, Operation op );
(C++23 起)

重设字符串大小以含有至多 count 个字符,用用户提供的操作 op 修改可能不确定的内容并设置长度。这样就避免了初始化大小合适的 std::string 时所产生的成本,当它打算作为要被填充的字符数组时,例如,C API 调用。

此函数执行下列步骤:

  1. 获得至少含有 count + 1 个字符的存储,并使其前 k 个字符等于 *this 的前 k 个字符,其中 kcount 与调用 resize_and_overwritethis->size() 的结果的较小者。令 p 代表指向该存储中首个字符的指针。
    • 相等性以如同检查 this->compare(0, k, p, k) == 0 确定。
    • [p + kp + count] 中的字符可能拥有不确定值。
  2. 求值 std::move(op)(p, count)。令 rstd::move(op)(p, count) 的返回值。
  3. [pp + r) 替换 *this 的内容(这会设置 *this 的长度为 r )。非法化所有指向范围 [pp + count] 中的指针与引用。

r 不具有整数式类型则程序非良构。若 std::move(op)(p, count) 抛出异常或修改 pcountr 不在范围 [0count] 中,或范围 [pp + r) 中的任何字符拥有不确定值,则行为未定义。

推荐实现避免不必要的复制与分配,例如通过使得 p 等于指向调用后为 *this 分配的字符存储的起始指针,若 count 小于或等于 this->capacity() 则该存储能等同于 *this 的既存存储。

参数

count - 字符串的最大可能的新大小
op - 用于设置字符串新内容的函数对象

返回值

(无)

异常

count > this->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()
{
    // A simple case, append only fruits[0]. The string size will be increased.
    std::string s{"Food: "};
    s.resize_and_overwrite(16, [sz = s.size()](char* buf, std::size_t buf_size)
    {
        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';
 
    // The size shrinking case. Note, that the user's lambda is always invoked.
    s.resize_and_overwrite(10, [](char* buf, int n)
    {
        return std::find(buf, buf + n, ':') - buf;
    });
    std::cout << "2. " << std::quoted(s) << '\n';
 
    std::cout << "3. Copy data until the buffer is full. Print data and sizes.\n";
    std::string food{"Food:"};
    const auto resize_to{27};
    std::cout << "Initially, 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] is the assignable range
            // p[0]..p[min(n, food_size) - 1] is the readable range
            // (contents initially equal to the original string)
 
            // Debug print:
            std::cout << "In Operation(); n: " << n << '\n';
 
            // Copy fruits to the buffer p while there is enough space.
            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)};
 
            // Debug print:
            std::cout << "In Operation(); final_size: " << final_size << '\n';
 
            assert(final_size <= n);
            return final_size; // Return value is the actual new length
                               // of the string, must be in range 0..n
        });
 
    std::cout << "Finally, food.size: " << food.size()
              << ", food.capacity: " << food.capacity()
              << ", food: " << std::quoted(food) << '\n';
}

可能的输出:

1. "Food: apple"
2. "Food"
3. Copy data until the buffer is full. Print data and sizes.
Initially, food.size: 5, food.capacity: 15, resize_to: 27, food: "Food:"
In Operation(); n: 27
In Operation(); final_size: 26
Finally, food.size: 26, food.capacity: 30, food: "Food: apple banana coconut"

参阅

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