Home > Enterprise >  Initialize a string with a char pointer with zero-copy
Initialize a string with a char pointer with zero-copy

Time:02-02

Say I am given a long and null-terminated cstring as char* text_ptr. I own text_ptr and I am responsible of free()ing it. Currently, I use text_ptr and free() it each time after use.

I try to improve memory safety a bit by wrapping it in a C class so that I can enjoy the benefit of RAII. There could be many ways to achieve it. A naive way is: string text_ptr(text_ptr);. However, by doing so, memory is copied once and I still need to manually free() my text_ptr. It would be better if I can avoid memory copy and free() (as this text_ptr is created frequently, performance could take a big hit if I copy it each time). My current thought:

Is it possible to transfer the ownership of text_ptr to a string text_str? Hypothetically, I do text_str.data() = text_ptr;.

Thanks

CodePudding user response:

std::string can't receive ownership of an external buffer. The best you can do is std::unique_ptr.

By default std::unique_ptr will use delete (or delete[]), but you need std::free(), so a custom deleter is required:

#include <cstdlib>
#include <memory>

struct FreeDeleter
{
    void operator()(void *p) const
    {
        std::free(p);
    }
};

int main()
{
    std::unique_ptr<char[], FreeDeleter> ptr((char *)malloc(42));
}

If you also store the length, you can construct a temporary std::string_view from pointer length when needed, to conveniently read the string.


Or, a oneliner: std::unique_ptr<char[], std::integral_constant<void(*)(void *), std::free>>.

Another one for C 20: std::unique_ptr<char[], decltype([](void *p){std::free(p);})>.

CodePudding user response:

An idea (not sure it’s a good one, tho)

#include <iostream>
#include <string_view>
#include <cstring>
#include <memory>

struct my_string_view : public std::string_view
{
  using std::string_view::string_view;
  std::shared_ptr<char[]> _data;
  explicit my_string_view( char * data ) 
    : std::string_view(data)
    , _data{data, free} 
    { }
};

void f( const my_string_view & s )
{
  std::cout << "f: \"" << s << "\"\n";
}

int main()
{
  my_string_view s( strdup( "Hello world!" ) );
  f( s );
  std::cout << "main: \"" << s << "\"\n";
}

(This version requires C 17. For older versions of the standard you’ll have to specify the default_deleter<char[]>() explicitly.)

  • Related