will a re-new of a TCHAR* array has negative/undefined effect? Or even maybe not recommended? Below code has been working fine so far. Need inputs. Thanks!
//e.g.
TCHAR *tc1 = new TCHAR[1];
// later:
//resize TCHARs
tc1 = new TCHAR[size1];
tc1[size1] = { L'\0' };
This is a memory leak. You need to delete anything created by a new call. If you do that, everything is fine:
//e.g.
TCHAR *tc1 = new TCHAR[1];
// later:
//resize TCHARs
delete [] tc1;
tc1 = new TCHAR[size1];
tc1[size1] = { L'\0' };
Although on an unrelated note, your last line is writing behind the array you allocated. That's not fine. But it has nothing to do with your allocation of memory, it's a mistake on it's own.
A lot of this can be avoided if you use a string class. Either std::string or if you are using the MFC, CString.
The negative effect of the "re-newing" is that you lose the pointer to the free-store memory originally allocated. It will remain occupied throughout the rest of your program, without any chance to reclaim it.
Of course, you may have some other pointer pointing to the memory, but that would be a very strange and unnecessarily complex piece of code.
Avoid all those problems by using std::vector instead of new[].
tc1 = new TCHAR[size1];
tc1[size1] = { L'\0' };
In addition to the memory leak, this is undefined behaviour because size1 is one past the last valid index.
Here's a std::vector example:
std::vector<TCHAR> tc1(1);
// later:
//resize TCHARs
tc1.resize(size1);
tc1[size1 - 1] = L'\0';
Perhaps even std::string or std::wstring is sufficient for your needs.
Related
When I run my program, it can run for a while, then all of the sudden, it experiences a huge memory leak. I traced it out using a snapshot of the heap when it crashed, and I have a mysterious char[] with the size of 232,023,801 Bytes. The minutes preceding crash have no unusual behavior until then. The only places where I use char arrays is in the following piece of code:
string ReadString(DWORD64 addr) {
char* buffer = new char[128];
bool validChar = true;
for (int c = 0; c < 128 && validChar; c++) {
buffer[c] = Mem.Read<char>(addr+ (0x1 * c), sizeof(char));
if (!isalnum(buffer[c]) && !ispunct(buffer[c]))
validChar = false;
}
string ret= string(buffer);
delete[] buffer;
return ret;
}
All this code should be doing is reading a few characters from memory, saving the char array to a string, cleaning up the array, and returning the string. How is the memory leak originating from here? Or does the char[] in the heap snapshot potentially point to another issue?
Assuming that string here is std::string:
You call string(buffer) which assumes that buffer is 0-terminated and allocates a new string. But your code doesn't ensure that buffer is actually 0-terminated, so this can cause undefined behavior, including potentially crashing or allocating too much memory for the string.
You probably want to use the string(buffer, size) constructor instead, which doesn't require buffer to be 0-terminated.
I'd also recommend avoiding the manual new/delete. One way to do this is to create an empty string and push_back the characters you read to it. This avoid the need for buffer.
I'm using VS2012. I'd rather be allocating memory for CString off of the heap, so given the code below:
Is CString csToken allocating memory from the stack or heap?
Do I need to free memory that csToken is using, or will it automatically be freed at the function termination?
TCHAR *sAllCodes = (TCHAR *) calloc(50000,sizeof(TCHAR)); // Dynamically use Heap memory to hold all pipe-delimited codes
TCHAR *sCode = (TCHAR *) calloc(128,sizeof(TCHAR)); // Dynamically use Heap memory to hold a single code
DWORD i = 0;
LoadAllCodes(&sAllCodes); // Custom function
CString csToken; // Declare the CString variable
csToken.Append(sAllCodes); // Assign the string to the Cstring variable
vector<CString> vAllCodes; // Declare the vector variable
vAllCodes = Split(csToken,L"|"); // Split the CString into a vector array
while ( i < (DWORD) vAllCodes.size())
{
if (vAllCodes[i].StringLength() > 0) // If there is a string in the vector item
{
_stprintf_s(sCode,128,L"%s",vAllCodes[i].GetString()); // Get the vector item and copy it into a string
// Do work on sCode here...
}
i++;
}
free(sAllCodes);sAllCodes=NULL;
free(sCode);sCode=NULL;
Your csToken variable is an instance of CString allocated on the stack, so you don't need to do anything to delete it: its destructor will do proper string cleanup when the scope of this variable terminates.
However, CString internally maintains a reference to the actual string, that is allocated on the heap.
CString actually uses a "COW" technique and reference counting, so several CString instances can share the same string, they can reference to the same string. However, these are CString implementation details.
The "take away" for a basic usage of CString is that if you have CString str you don't have to pay attention to str cleanup: it will be automatically managed by CString destructor.
Moreover, I'd like to take this occasion to make a few notes on your code, with the spirit of improving it.
Use std::vector
You have these allocations at the top of your posted code:
TCHAR *sAllCodes = (TCHAR *) calloc(50000,sizeof(TCHAR));
TCHAR *sCode = (TCHAR *) calloc(128,sizeof(TCHAR));
and then you have the corresponding free calls at the bottom:
free(sAllCodes);sAllCodes=NULL;
free(sCode);sCode=NULL;
Note however that this code is not exception safe: in fact, if any code between the calloc() and the free() calls happens to throw a C++ exception, the memory allocated on the heap for sAllCodes and sCode will not be released.
In a more modern and more practical C++ style, you could use std::vector instead of calloc() to allocate the memory on the heap, and automatically free it, thanks to std::vector destructor (just like for CString!).
Just substitute the calloc() calls with:
std::vector<TCHAR> allCodes(50000);
std::vector<TCHAR> code(128);
and just delete the free() calls! :)
Besides being simpler and shorter, your code becomes also exception-safe; in fact, if a C++ exception is thrown, vector destructor is automatically called, and the allocated memory is released.
If you want to access vector data, you can use its data() member function.
If you want to set the initial vector content to all 0s, you can use the vector v(count, 0) constructor overload.
Use C++-style casts
In your code you have a C-style (DWORD) cast. C-style casts are bad; consider using C++-style casts instead. In your case, you might want a static_cast<DWORD>(...).
Use CString::IsEmpty() to improve readability
You have an if in your code like this:
if (vAllCodes[i].StringLength() > 0)
CString offers a convenient IsEmpty() method, that is more readable:
if (! vAllCodes[i].IsEmpty())
....
Notes on _stprintf_s() and "magic numbers"
You use _stprintf_s() like this:
_stprintf_s(sCode,128,L"%s",vAllCodes[i].GetString());
But note that if you use the TCHAR model, for coherence you should use _T("%s") in the format specifier.
If you want to just use Unicode strings and L"%s" (which I suggest), then use the corresponding Unicode-only swprintf_s(), and get rid of TCHAR and just use wchar_t instead.
Note also that, instead of using the "magic number" 128, you may want to use sCode.size() (assuming sCode becomes an instance of std::vector, as I suggested above). So, if you change the size of the vector, you don't have to update also the "magic number" 128 (with these magic numbers, there are basically bugs waiting to happen :)
The updated code might be something like:
swprintf_s(code.data(), code.size(), L"%s", vAllCodes[i].GetString());
CString csToken variable is allocated on the stack, but once some string is assigned to it, it allocates its internal buffers on the heap.
You don't need to release any memory occupied by csToken explicity, it will be released once csToken variable goes out of scope, and its destructor is called.
Anything that is allocated on the stack will be freed once a function goes out of scope. Anything on the heap must be explicitly freed.
csToken hasn't been allocated with the new keyword, so it is on the stack, rather than the heap.
Finally, I see that you are using C++, and it is very taboo to use free() and malloc() in C++. You should use the new and delete keywords.
EDIT:
This line can be rewritten:
TCHAR *sAllCodes = (TCHAR *) calloc(50000,sizeof(TCHAR));
as:
TCHAR *sAllCodes = new TCHAR(5000);
This is how to use the new keyword.
I'm kind of new when it comes to memory management in C++. I read that if you create a class with the new keyword you must delete the object to free its memory. I also read that primitive types, such as int, char and bool, are created on the stack, which means they get deleted when they go out of scopes.
But what about primitive types created with the new keyword? Do I need to explicitly call delete? Are these created on the heap like classes? Or since they are primitive do they still get created on the stack?
I am asking because I am allocating a LPTSTR using the new keyword, but I am worried that if I do not call delete that the memory will never be freed. Here is my code with the bare question in the comments:
#include <Windows.h>
#include <tchar.h>
#include <string>
#ifdef _UNICODE
typedef std::wstring Str;
#else // ANSI
typedef std::string Str;
#endif
Str GetWndStr(HWND hwnd) {
const int length = GetWindowTextLength(hwnd);
if (length != 0) {
LPTSTR buffer = new TCHAR[length + 1]; // Allocation of string
GetWindowText(hwnd, buffer, length + 1);
Str text(buffer);
delete buffer; // <--- Is this line necessary?
return text;
} else {
return _T("");
}
}
Do I need to call delete? Awhile back, I tried using GlobalAlloc() and GlobalFree(), but during runtime I got an error saying something about illegally modifying the stack, I do not have an exact error message as this was awhile ago. Also, in addition to your answer, if you would like to give me resources you found helpful to learn more about C++ memory management, that would be nice.
For every new there must be a delete and for every new[] there must be a delete[]. Notice that the memory allocated with new[] must be deleted with delete[], which is not the case in the posted code.
A smart pointer can be used, boost::scoped_array for example, which will perform the delete[] in its destructor (or reset() function). This is particularly useful if exceptions can be thrown after the call to new[]:
boost::scoped_array<TCHAR> buffer(new TCHAR[length + 1]);
GetWindowText(hwnd, buffer.get(), length + 1);
Str text(buffer.get()); // buffer will be deleted at end of scope.
Your array is allocated with new[] and therefore must be deleted with delete[] (not delete).
Your explicit dynamic allocation is also unnecessary:
Str text(length+1, 0);
GetWindowText(hwnd, &text[0], length + 1);
text.resize(length); // remove NUL terminator
return text;
In C++03 there's some justification needed, whether string and wstring actually allocate contiguous memory, suitable for passing as a buffer. It's not guaranteed by the C++03 standard, but it is in fact true in MSVC++. If you don't want to rely on that fact, then it is guaranteed for vector, so you can use that for the buffer:
std::vector<TCHAR> buffer(length+1);
GetWindowText(hwnd, &buffer[0], length + 1);
return Str(buffer.begin(), buffer.end() - 1);
It is pretty rare to directly use new[] in C++. In both cases, my vector or string buffer is an automatic variable, so I don't have to do anything special to make sure that it is destroyed correctly when its scope ends.
YES (unless you use smart pointers or similar to delete it for you)
Yes, the rule is very simple. Everything you allocate with new needs to be deallocated with delete; and everything allocated with new[] needs to be deallocated with delete[].
To reduce the chances of error, it's best to use containers, smart pointers or other RAII-style objects to manage dynamic resources, rather than remembering to use delete yourself.
Sure, no matter what type was allocated. It still have memory space.
I was reviewing my skills with pointers and buffer in C++. I tried the code below and everything works fine. No leaks, no crash, nothing.
To be honest I didn't expect this.
When I call char* buf2 = new char[strlen(buf)] I didn't expect srlen(buf) returning the right size. I always thought that strlen
needs a NULL terminated string to work. Here it is not the case so why it is working this code?
int main(){
const char* mystr = "mineminemine";
char* buf = new char[strlen(mystr)];
memcpy(buf, mystr, strlen(mystr));
char* buf2 = new char[strlen(buf)];
memcpy(buf2, buf, strlen(buf));
delete[] buf2;
delete[] buf;
}
That's called undefined behavior - the program appears working but you can't rely on that.
When memory is allocated there happens a null character somewhere that is close enough to the start of the buffer and the program can technically access all memory between that null character and the start of the buffer so you don't observe a crash.
You can't rely on that behavior. Don't write code like that, always allocate enough space to store the terminating null character.
Consider another way to do the same thing:
int main(){
std::string mystr = "mineminemine";
std::string mystr2 = mystr;
}
Internally you have a buffer with a null terminating character added. When you copy a standard string you don't have to worry about keeping track of the start and end of the buffer.
Now considering the lifetime of the strings these two variables are declared on the stack and destroyed when main goes out of scope (e.g. terminationa). If you need strings to be shared amongst objects and you do not necessarily know when they will be destroyed I recommend considering using boost shared pointers.
I'm relatively novice when it comes to C++ as I was weened on Java for much of my undergraduate curriculum (tis a shame). Memory management has been a hassle, but I've purchased a number books on ansi C and C++. I've poked around the related questions, but couldn't find one that matched this particular criteria. Maybe it's so obvious nobody mentions it?
This question has been bugging me, but I feel as if there's a conceptual point I'm not utilizing.
Suppose:
char original[56];
cstr[0] = 'a';
cstr[1] = 'b';
cstr[2] = 'c';
cstr[3] = 'd';
cstr[4] = 'e';
cstr[5] = '\0';
char *shaved = shavecstr(cstr);
// various operations, calls //
delete[] shaved;
Where,
char* shavecstr(char* cstr)
{
size_t len = strlen(cstr);
char* ncstr = new char[len];
strcpy(ncstr,cstr);
return ncstr;
}
In that the whole point is to have 'original' be a buffer that fills with characters and routinely has its copy shaved and used elsewhere.
To clarify, original is filled via std::gets(char* buff), std::getline(char* buff, buff_sz), std::read(char* buff, buff_sz), or any in-place filling input reader. To 'shave' a string, it's basically truncated down eliminating the unused array space.
The error is a heap allocation error, and segs on the delete[].
To prevent leaks, I want to free up the memory held by 'shaved' to be used again after it passes through some arguments. There is probably a good reason for why this is restricted, but there should be some way to free the memory as by this configuration, there is no way to access the original owner (pointer) of the data.
I assume you would replace original by cstr, otherwise the code won't compile as cstr is not declared.
The error here is that the size of the allocated array is too small. You want char* ncstr = new char[len+1]; to account for the terminating \0.
Also, if you delete shaved right after the function returns, there is no point in calling the function...
[*] To go a bit deeper, the memory used for cstr will be released when the containing function returns. Usually such static strings are placed in constants that live for the entire duration of the application. For example, you could have const char* cstr="abcde"; outside all your functions. Then you can pass this string around without having to dynamically allocate it.
Assuming you meant to use cstr instead of cstrn...
You should not be deleting cstr. You should be deleting shaved.
You only delete the memory that was allocated with new. And delete[] memory that was allocated with new[].
shaved is simply a variable that holds a memory address. You pass that memory address to delete[] to get rid of the memory. shaved holds the memory address of the memory that was allocated with new[].