名前空間
変種
操作

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

From cppreference.com
< cpp‎ | string‎ | basic string
 
 
 
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. count + 1 文字を含む連続したストレージを取得し、その最初の k 文字を *this の最初の k 文字と同じにします。ここで k は、countresize_and_overwrite を呼び出す前の size() の結果のうち小さい方です。ストレージの最初の文字へのポインタを p とします。
    • 等価性は、this->compare(0, k, p, k) == 0 をチェックすることで決定されるかのように行われます。
    • [p + kp + count] の文字は不確定な値を持つ場合があります。
  2. std::move(op)(p, count) を評価し、その戻り値を r とします。
  3. *this の内容を [pp + r) で置き換えます (*this の長さを r に設定します)。範囲 [pp + count] へのすべてのポインタと参照を無効にします。

rinteger-like 型でない場合、プログラムは不正です。

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

  • std::move(op)(p, count) が例外をスローします。
  • std::move(op)(p, count)p または count を変更します。
  • r が範囲 [0count] にありません。
  • 範囲 [pp + r) の文字は不確定な値を持っています。

実装は、たとえば、呼び出し後に *this に割り当てられた文字のストレージの先頭へのポインタと p を等しくすることで、不要なコピーと割り当てを避けることが推奨されます。これは、countcapacity() 以下の場合、*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()
{
    // 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) 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';
 
    // The size shrinking case. Note, that the user's lambda is always invoked.
    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. 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"

[編集] 関連項目

格納されている文字数を変更する
(public member function) [編集]
English 日本語 中文(简体) 中文(繁體)