Turxan Dünya
Turxan Dünya

Reputation: 13

String allocation problem on each iteration

l have a string like "hello_1_world". And in each iteration l want to increment "1" part. "hello_2_world", "hello_3_world" etc... So l can not use const char* or string_view. l have to allocate new memory in every iteration by using std::string. But, l do not want to because of performance issue. Could you suggest a solution?

So, my code is like below. Guess index is incrementing each time.

std::string value{"hello_" + std::to_string(index) + "_world"};

l tried so many ways. And one of them is like below:

string_view result(value, 39);

And concat something but again. l cant modify string_view

Upvotes: 0

Views: 138

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 595827

Do you really need a std::string, or will a simple char[] suffice? If so, then try something like this:

// a 32bit positive int takes up 10 digits max...
const int MAX_DIGITS = 10;
char value[6 + MAX_DIGITS + 6 + 1];

for(int index = 0; index < ...; ++index) {
    std::snprintf(value, std::size(value), "hello_%d_world", index);
    // use value as needed...
}

Alternatively, if you don't mind having leading zeros in the number, then you can update just that portion of the buffer on each iteration:

const int MAX_DIGITS = ...; // whatever you need, up to 10 max
char value[6 + MAX_DIGITS + 6 + 1];

std::strcpy(value, "hello_");
std::strcpy(&value[6 + MAX_DIGITS], "_world");

for(int index = 0; index < ...; ++index) {
    std::snprintf(&value[6], MAX_DIGITS, "%0.*d", MAX_DIGITS, index);
    // use value as needed...
}

If you really need a std::string, then simply pre-allocate it before the iteration, and then fill in its existing memory during the iteration, similar to a char[]:

const int MAX_DIGITS = 10;

std::string value;
value.reserve(6 + MAX_DIGITS + 6); // allocate capacity

for(int index = 0; index < ...; ++index) {
    value.resize(value.capacity()); // preset size, no allocation when newsize <= capacity

    std::copy_n("hello_", 6, value.begin());

    auto ptr = std::to_chars(&value[6], &value[6 + MAX_DIGITS], index).ptr;
    /* or:
    auto numWritten = std::snprintf(&value[6], MAX_DIGITS, "%d", index);
    auto ptr = &value[6 + numWritten];
    */

    auto newEnd = std::copy_n("_world", 6, ptr);

    value.resize(newEnd - value.data()); // no allocation when shrinking size

    // use value as needed...
}

Alternatively, with leading zeros:

const int MAX_DIGITS = ...; // up to 10 max

std::string value(6 + MAX_DIGITS + 6, '\0');

std::copy_n("hello_", 6, value.begin());
std::copy_n("_world", 6, &value[6 + MAX_DIGITS]);

for(int index = 0; index < ...; ++index) {
    std::snprintf(&value[6], MAX_DIGITS, "%0.*d", MAX_DIGITS, index);
    // use value as needed...
}

Upvotes: 1

Ga&#235;tan Faucher
Ga&#235;tan Faucher

Reputation: 11

you could use a std::stringstream to construct the string incrementally:

std::stringstream ss;
ss << "hello_";
ss << index;
ss << "_world";
std::string value = ss.str();

Upvotes: 0

Related Questions