Reputation: 31256
Suppose I do the following:
char *get_data(...) {
char *c_style = (char *) malloc(length * sizeof(char));
load_c_string_with_my_c_function(c_style, length, input);
return c_style;
}
int main() {
std::string data(get_data(...));
// free(data.c_str()); ?? -- are the malloc'd bytes now managed?
return 0;
}
Is there any way to release the memory that get_data()
allocated? Would the commented free(data.c_str());
Work?
Upvotes: 1
Views: 504
Reputation: 16876
You can't call call free(data.c_str());
or anything like that. std::string
manages its own memory and even the pointer that you get from c_str()
is invalidated automatically as soon as the std::string
goes out of scope.
You do, however, need to free the c_style
returned from the function call. The std::string
may handle its own memory, but it is only a copy of the malloc
'd memory that isn't managed.
Do this:
int main() {
char *result = (get_data(...)
std::string data(result);
// free(data.c_str()); ?? -- are the malloc'd bytes now managed?
free(result);
return 0;
}
Upvotes: 2
Reputation: 385264
Is there any way to release the memory that
get_data()
allocated?
No, you lost your pointer to it.
Would the commented
free(data.c_str());
Work?
No. The std::string
copied your data into a new string that it owns and manages. You cannot legally de-allocate the std::string
's own allocated memory, and it would not solve the problem of having to de-allocate your original allocated memory.
Either use std::string
throughout (preferred!) or capture the pointer inside main
first:
int main()
{
auto cstr = get_data(...);
std::string data(cstr);
free(cstr);
}
Trouble is, this isn't exception-safe, which is why we have nice things like std::string
in the first place. It can be solved with some liberal try
and catch
but it'll be ugly.
Also, since you already have get_data
, presumably for a reason, you might consider a string_view
over the actual memory that you already allocated, unless you really need data
to be an owning copy.
int main()
{
auto cstr = get_data(...);
std::string_view data(cstr); // no copy! just features
free(cstr);
}
(Comments elsewhere indicate that this may be what you really wanted.)
Now experiment with having get_data
return something with clear ownership & lifetime semantics (std::unique_ptr
? std::vector
? std::string
? .. lol) and you're golden.
Upvotes: 2
Reputation: 180935
Once you do
std::string data(get_data(...));
there is no way to get the pointer back that get_data()
returned so you will leak that memory. To fix this just have get_data()
return a std::string
in the first place so you don't have to worry about memory management at all. That would give you
std::string get_data(...) {
std::string data(length, '\0');
load_c_string_with_my_c_function(data.data(), length, input); // requires C++17
// load_c_string_with_my_c_function(&data[0], length, input); // use this for pre-C++17 compilers
return data;
}
and now no memory leak. If you can't do this then you need to capture the pointer, use it to initialize the string, and then free the pointer like
char* ret = get_data(...);
std::string data(ret);
free(ret);
Upvotes: 5
Reputation: 36469
You can't delete the pointer, you aren't keeping a reference to it. You need to do:
int main() {
char* cstr = get_data(...);
std::string data(cstr);
free(cstr);
return 0;
}
Or much better write your data into the string directly:
std::string get_data(...) {
std::string data(length, '\0');
load_c_string_with_my_c_function(&data[0], data.size(), input);
return data;
}
You may need to add 1 to the length of the std::string
and/or pass data.size()-1
to load_c_string_with_my_c_function
depending on the specification of the length
parameter of load_c_string_with_my_c_function
.
Upvotes: 1