[SOLVED] std::to_string return empty string when using std::allocator

Issue

I got the empty return of std::to_string when I use std::allocator. The code is:

#include <iostream>
#include <memory>
#include <string>

int main()
{
    std::allocator<std::string> allocatorStr;
    auto const pStr = allocatorStr.allocate(5);
    for (int i = 0; i < 5; ++i) { *(pStr + i) = std::to_string(i); }
    for (int i = 0; i < 5; ++i) { std::cout << *(pStr + i) << std::endl; }

    return 0;
}

But if I change the line *(pStr + i) = std::to_string(i);to *(pStr + i) = "string"; I could get non-empty output.
I don’t know where is wrong. Thank you very much for your help.

Solution

To quote from cppreference, (emphasis mine):

[allocate] … allocates n * sizeof(T) bytes of uninitialized storage

In other words, there are no valid std::string objects there yet and trying to use them (even as the target of a copy) invokes undefined behaviour (I got a segfault).

To fix this, use placement new to construct the needed std::string objects immediately after calling allocate:

auto pStr = allocatorStr.allocate(5);
for (int i = 0; i < 5; ++i) { new (pStr + i) std::string; }
...

Then, it works


Edit: Responding to @user17732522’s comment below (which makes a lot of sense), there are advantages to using std::allocator_traits::construct instead of placement new; the comment explains what they are. This does essentially the same job as placement new, but in a more flexible way (from the allocator’s perspective). And since one is doing that, one might as well also use std::allocator_traits::allocate, since this has a few advantages too.

The code then becomes:

using MyAllocatorTraits = std::allocator_traits <decltype (allocatorStr)>;
auto pStr = MyAllocatorTraits::allocate (allocatorStr, 5);
for (int i = 0; i < 5; ++i) { MyAllocatorTraits::construct (allocatorStr, pStr + i); }
...

Updated live demo

Answered By – Paul Sanders

Answer Checked By – Robin (BugsFixing Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *