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