Skip to main content

std::string resize_and_overwrite() method

// Non const version only
template< class Operation >
constexpr void resize_and_overwrite( size_type count, Operation op );

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).

Invalidation

Invalidates all pointers and references to the range [ p, p + count ].

important

The program is ill-formed if r does not have an integer-like type.

Undefined Behavior

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.

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)

Complexity

important

This section requires improvement. You can help by editing this doc page.

Exceptions

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

Undefined Behavior

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 (strong exception guarantee).

Notes

Invalidation

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().

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 capacity().

Feature testing macro: __cpp_lib_string_resize_and_overwrite

Example

Main.cpp
#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';
}
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"
This article originates from this CppReference page. It was likely altered for improvements or editors' preference. Click "Edit this page" to see all changes made to this document.
Hover to see the original license.

std::string resize_and_overwrite() method

// Non const version only
template< class Operation >
constexpr void resize_and_overwrite( size_type count, Operation op );

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).

Invalidation

Invalidates all pointers and references to the range [ p, p + count ].

important

The program is ill-formed if r does not have an integer-like type.

Undefined Behavior

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.

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)

Complexity

important

This section requires improvement. You can help by editing this doc page.

Exceptions

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

Undefined Behavior

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 (strong exception guarantee).

Notes

Invalidation

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().

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 capacity().

Feature testing macro: __cpp_lib_string_resize_and_overwrite

Example

Main.cpp
#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';
}
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"
This article originates from this CppReference page. It was likely altered for improvements or editors' preference. Click "Edit this page" to see all changes made to this document.
Hover to see the original license.