How do I do this thing.
char* ToString(int num) {
char* str = new char[len(num)];
//conversion
return str;
}
And by calling this.
string someStr = ToString(someInt);
Should I free the someStr here?
I know I always need to delete whenever I use new.
And what if I call this function multiple times, do I allocate memory and just leaving them behind not using it?
You should avoid this practice altogether. Either return a std::unique_ptr, or deal with std::string directly. It is not clear from your code what exactly you are trying to do, so I can't offer specific solutions.
Note that this initialization:
string someStr = ToString(someInt);
will only work properly if you return a null-terminated string, but it leaks resources regardless.
See this related post.
You need to call delete once for every call to ToString. You also can't initialise a std::string with an allocated char array in the way your question hints at - that'd leak the returned memory, with your someStr variable having copied it.
The easiest/neatest thing to do would be to change ToString to return std::string instead. In this case, memory used by the string will be automatically deleted when the caller's variable goes out of scope.
I ran your code under valgrind with --leak-check=full, it reports num size of memory leak.
Call new/delete, new [] /delete [] in pair is the only way to keep memory cycled.
I am not sure what's you trying to do, if you want to convert integer types to string, C++ has a few options:
// std::to_string(C++11) e.g:
{
std::string str = std::to_string(num)
}
// std::stringstream e.g:
{
std::string str;
std::stringstream ss;
ss << num;
ss >> str;
}
// boost::lexical_cast e.g:
{
std::string str = boost::lexical_cast<std::string>(num);
}
// itoa(c function)
{
char buf[MAX_INT_DIGITS]; // MAX_INT_DIGITS == 12 ("-2147483648\0")
itoa(num, buf, 10);
std::string str(buf);
}
You're ToString function should return a std::string, if you then just assign the value to a std::string. No reason to deal with dynamically allocated memory here.
someStr is a copy. You have allready a leak. You need to temporally save the value of the returned pointer and after constructing the string delect it. This is normaly the job of the smart pointers.
EDIT:
No,
char* temp = strs; delete [] str; return temp;
will something undefined. But:
char* temp =ToString(someInt); string someStr(temp);delete []temp;
will work. But this is only for you to understand the idea. This can be made for you if you return a unique_ptr. And I'm assuming this is a kind of general question of returning a memory that have to be free after that, in with case unique_ptr and shared_ptr are a solution. In this particular case you can just create a string, modify it and return it simply. All the memory manage will be made for you by the string class. If you really only need to allocate “space” in the string, you can do:
String Str; Str.reserve(len(num));
Related
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?
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);
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.
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;
}
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.
I have an issue where I need a vector of const char* but for some reason whenever I try adding something nothing happens. Here is the code sample in question.
std::vector<const char*> getArgsFromFile(char* arg) {
std::ifstream argsFile(arg);
std::vector<const char*> args;
while (!argsFile.eof()) {
std::string temp;
argsFile >> temp;
args.push_back(temp.c_str());
}
args.pop_back();
return args;
}
The strange part is if I make this change
std::vector<const char*> getArgsFromFile(char* arg) {
std::ifstream argsFile(arg);
std::vector<const char*> args;
while (!argsFile.eof()) {
std::string temp;
argsFile >> temp;
const char* x = "x";
args.push_back(x);
}
args.pop_back();
return args;
}
It will add 'x' to the vector but I can't get the value of temp into the vector. Any thoughts? Help would be greatly appreciated. Thanks!
A const char* is not a string, but merely a pointer to some memory, usually holding some characters. Now std::string under the hood either holds a small region of memory (like char buff[32]) or, for larger strings, keeps a pointer to memory allocated on the heap. In either case, a pointer to the actual memory holding the data can be obtained via string::c_str(). But when the string goes out of scope that pointer no longer points to secured data and becomes dangling.
This is the reason why C++ introduced methods to avoid direct exposure and usage of raw pointers. Good C++ code avoid raw pointers like the plague. Your homework is for poor/bad C++ code (hopefully only to learn the problems that come with such raw pointers).
So, in order for the pointers held in your vector to persistently point to some characters (and not become dangling), they must point to persistent memory. The only guaranteed way to achieve that is to dynamically allocate the memory
while (!argsFile.eof()) {
std::string temp;
argsFile >> temp;
char* buff = new char[temp.size()+1]; // allocate memory
std::strncpy(buff,temp.c_str(),temp.size()+1); // copy data to memory
args.push_back(buff); // store pointer in vector
}
but then the memory allocated in this way will be leaked, unless you de-allocate it as in
while(!args.empty()) {
delete[] args.back();
args.pop_back();
}
Note that this is extremely bad C++ code and not exception safe (if an exception occurs between allocation and de-allocation, the allocated memory is leaked). In C++ one would instead use std::vector<std::string> or perhaps std::vector<std::unique_ptr<const char[]> (if you cannot use std::string), both being exception safe.
Use a standard-library-based implementation
Guideline SL.1 of the C++ coding guidelines says: "Use the standard library whenever possible" (and relevant). Why work so hard? People have already done most of the work for you...
So, using your function's declaration, you could just have:
std::vector<std::string> getArgsFromFile(char* arg) {
using namespace std;
ifstream argsFile(arg);
vector<string> args;
copy(istream_iterator<string>(argsFile),
istream_iterator<string>(),
back_inserter(args));
return args;
}
and Bob's your uncle.
Still, #Walter's answer is very useful to read, so that you realize what's wrong with your use of char * for strings.
Is it possible to add a string to a string pointer in C++?
Not working example:
String* temp;
temp[0] = "string";
Just like it's possible in:
String temp[3];
temp[0] = "string";
Before suggesting to just use a normal array or copy it to a different fixed array, the string pointer needs to be returned in a function. Eg.
String* SomeClass::toArray(String str)
I am also open to other suggestions how I can return an array from this function.
Independing of what is String this code snippet
String* temp;
temp[0] = "string";
if it is compiled results in undefined behaviour because the pointer temp either has an indeterminate value (if it is a local variable) or NULL and you may not derefence it.
Provided that this code snippet
String temp[3];
temp[0] = "string";
is valid you could write for example
String* other_temp = temp;
other_temp[0] = "string";
you can't add anything to POINTER, pointer is just pointing to some memory.
You need first to have some instance, like in your second example String temp[3]; you are creating three instances of String.
So String temp; will create local instance of String, then to get it's pointer you can use String * tempPtr = &temp;, but I don't see why you would want that, as you can use temp as is... like temp.clear(); or whatever functions the class String has (see it's API).
Edit about returning String pointer.
That's sort of unfortunate C++ API design. So who will own the memory of that instance?
For example:
String* SomeClass::toArray(String str) {
String result;
// BUG, DO NOT DO THIS!
return &result; // returns pointer to local stack variable
// which gets released *here*, invalidating the pointer
}
String* SomeClass::toArray(String str) {
String *result = new String;
return result; // returns pointer to global heap
// now if the upper layer of code will not call "delete" on it
// you have memory leak
}
BTW, from the "toArray" name it looks like you want array of String instances, not String pointer. So that functions should be rather defined as String[] SomeClass::toArray(String str), still having the same problem with memory ownership.
What I would do is not return an array.
maybe void SomeClass::toArray(const String & str, std::vector<String> & array), filling up the data into array vector.
I do not know how much you use C++ on arduino, if std::vector is OK, or not, but having a class for String feels like vector<> will be OK too, especially if you are wasting your stack by passing copy instance of String instead of reference. (unless String is some macro/typedef for char[], please, don't tell me that... I mean, even C++ can be written in low memory footprint way, you don't have to hardwire arrays everywhere, if you avoid unnecessary allocation of temporary instances of C++ classes).
Here is part of my code:
extern "C" REGISTRATION_API int extreme(char* lKey)
{
string s1;
char *p=NULL;
try
{
ifstream myfile ("extreme.txt");
int i=0;
if (myfile.is_open())
{
while (getline(myfile,s1))
{
switch (i)
{
case 1:
strcpy(p,s1.c_str());
lKey=p;
break;
//continue here
}
}
}
}
Now when I call this function from external application, I get this error:
AccessViolationException:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
The problem is due to this:
lKey=p;
How can I assign the lKey to p?
You need to pre-allocate the memory which you pass to strcpy. I.e. a p = new char[s1.length()+1]; will do it (+1 for the terminating 0 character). However, it's not a good idea to mix up std::string and C string routines for no good reason. Better stick with std::string, it will save you a LOTS of trouble.
Also lKey=p won't work either -- it just copies the local address of p into the local variable lKey. The caller won't even see a difference.
Actually the problem is strcpy(p,s1.c_str()); since p is never set to anything but NULL.
Remember that a char* is just an address of a memory location. You need to have memory allocated at the address.
In your code you don't have memory allocated to use and you didn't set p to point to that memory address.
strcpy does not allocate a buffer, it just takes a memory address to copy the data to.
If you are passing a buffer into the function then you probably want simply this (and remove p)
strcpy(lKey, s1.c_str());
Eliminate p (it is doing nothing here), and copy the data from s1 directly to lkey
Not to beat on you, but the indentation scheme is a travesty, please cop a good style from somewhere ( google 1tbs )
Okay the previous question was answered clearly, but i found out another problem.
What if I do:
char *test(int ran){
char *ret = new char[ran];
// process...
return ret;
}
And then run it:
for(int i = 0; i < 100000000; i++){
string str = test(rand()%10000000+10000000);
// process...
// no need to delete str anymore? string destructor does it for me here?
}
So after converting the char* to string, I don't have to worry about the deleting anymore?
Edit: As answered, I have to delete[] each new[] call, but on my case its not possible since the pointer got lost, so the question is: how do I convert char to string properly?
Here you are not converting the char* to a [std::]string, but copying the char* to a [std::]string.
As a rule of thumb, for every new there should be a delete.
In this case, you'll need to store a copy of the pointer and delete it when you're done:
char* temp = test(rand()%10000000+10000000);
string str = temp;
delete[] temp;
You seem to be under the impresison that passing a char* into std::string transfers ownership of the allocated memory. In fact it just makes a copy.
The easiest way to solve this is to just use a std::string throughout the entire function and return it directly.
std::string test(int ran){
std::string ret;
ret.resize(ran - 1); // If accessing by individual character, or not if using the entire string at once.
// process... (omit adding the null terminator)
return ret;
}
Yes, yes you do.
If you are using linux/os x, look into something like valgrind which can help you with memory issues
You can change your test function so that it returns a string instead of char *, this way you can delete [] ret in the test function.
OR you could just use a string in test as well and not have to worry about new/delete.
You must call delete for every new otherwise you will leak memory. In the case you have shown you are throwing away the pointer, if you must leave the function as returning a char* then you will need to use two lines to create the std::string so you can retain a copy of the char* to delete.
A better solution would be to rewrite your test() function to return a std::string directly.
You need to do something like this:
for(int i = 0; i < 100000000; i++){
int length = rand()%10000000+10000000;
char* tmp = test(length);
string str(tmp);
delete[length] tmp;
}
This deletes the allocated char-array properly.
By the way, you should always zero-terminate a string if you create it this way (i.e. inside the function test), otherwise some functions can easily get "confused" and treat data behind your string as part of it, which in the best case crashes your application, and in the worst case creating a silent buffer overflow leading to undefined behaviour at a later point, which is the ultimate debugging nightmare... ;)