cpp / latest / string / basic_string / resize_and_overwrite.html /

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

template< class Operation >
constexpr void resize_and_overwrite( size_type count, Operation op );
(since C++23)

Resizes the string to contain at most count characters, using the user-provided operation op to modify the possibly indeterminate contents and set the length. This avoids the cost of initializing a suitably-sized std::string when it is intended to be used as a char array to be populated by, e.g., a C API call.

This function performs following steps:

  1. Obtains a contiguous storage that contains count + 1 characters, and makes its first k characters equal to the first k characters of *this, where k is the smaller of count and the result of this->size() before the call to resize_and_overwrite. Let p denote the pointer to the first character in the storage.
    • The equality is determined as if by checking this->compare(0, k, p, k) == 0.
    • The characters in [p + k, p + count] may have indeterminate values.
  2. Evaluates std::move(op)(p, count). Let r be the return value of std::move(op)(p, count).
  3. Replaces the contents of *this with [p, p + r) (which sets the length of *this to r). Invalidates all pointers and references to the range [p, p + count].

The program is ill-formed if r does not have an integer-like type. The behavior is undefined if std::move(op)(p, count) throws an exception or modifies p or count, r is not in the range [0, count], or any character in range [p, p + r) has an indeterminate value.

Implementations are recommended to avoid unnecessary copies and allocations by, e.g., making p equal to the pointer to beginning of storage of characters allocated for *this after the call, which can be identical to the existing storage of *this if count is less than or equal to this->capacity().

Parameters

count - the maximal possible new size of the string
op - the function object used for setting the new contents of the string

Return value

(none).

Exceptions

std::length_error if count > this->max_size(). Any exceptions thrown by corresponding Allocator.

If an exception is thrown from std::move(op)(p, count), the behavior is undefined. Otherwise, if an exception is thrown, this function has no effect.

Notes

resize_and_overwrite invalidates all iterators, pointers, and references into *this, regardless whether reallocation occurs. Implementations may assume that the contents of the string are not aliased after the call to resize_and_overwrite.

Feature testing macro: __cpp_lib_string_resize_and_overwrite.

Example

Link to test the example: 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';
}

Possible output:

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"

See also

changes the number of characters stored
(public member function)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/string/basic_string/resize_and_overwrite