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