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 для модификации возможно неопределенного содержимого и установки длины. Это позволяет избежать затрат на инициализацию строки std::string подходящего размера, когда она предназначена для использования в качестве массива символов, который будет заполняться, например, вызовом C API.

Эта функция выполняет следующие шаги:

  1. Получает непрерывную область памяти, содержащую count + 1 символов, и делает её первые k символов равными первым k символам * this , где k — меньшее из значений count и результата вызова size ( ) до вызова resize_and_overwrite . Обозначим через 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 после вызова, которое может совпадать с существующим хранилищем * this , если count меньше или равно capacity ( ) .

Содержание

Параметры

count - максимально возможный новый размер строки
op - функциональный объект, используемый для установки нового содержимого строки

Исключения

std::length_error если count > max_size ( ) . Любые исключения, выброшенные соответствующим 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[]{"яблоко", "банан", "кокос", "дата", "бузина"};
int main()
{
    // Простой случай, добавление только fruits[0]. Размер строки будет увеличен.
    std::string s{"Еда: "};
    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
(Примечание: Согласно требованиям, HTML-теги и атрибуты не переведены, термин `std::quoted` как специфический для C++ оставлен без изменения)(s) << '\n';
    // Случай уменьшения размера. Обратите внимание, что пользовательская лямбда всегда вызывается.
    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{"Еда:"};
    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: " << food.capacity()
              << ", еда: " << std::quoted
(Примечание: Согласно требованиям, HTML-теги и атрибуты не переведены, термин `std::quoted` как специфический для C++ оставлен без перевода)(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"

Смотрите также

изменяет количество хранимых символов
(публичная функция-член)