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呼び出しなどで埋められるchar配列として使用されることを意図した std::string を適切なサイズで初期化するコストを回避できます。

この関数は以下の手順を実行します:

  1. 連続したストレージを取得し、その最初の k 文字を * this の最初の k 文字と等しくする。ここで k count 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 integer-like type でない場合、プログラムは不適格(ill-formed)です。

以下のいずれかの条件が満たされる場合、動作は未定義です:

  • 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 - 文字列の新しい内容を設定するために使用される関数オブジェクト

例外

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[]{"apple", "banana", "ココナッツ", "日付", "エルダーベリー"};
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(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 << "Finally, 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"

関連項目

格納されている文字数を変更する
(公開メンバ関数)