Using std::make_unique with the GetProfileBinary function call - c++

I have seen this answer (Advantages of using std::make_unique over new operator) where it states:
Don't use make_unique if you need a custom deleter or are adopting a raw pointer from elsewhere.
This is is my code:
void CAutomaticBackupSettingsPage::GetLastBackupDate(COleDateTime& rBackupDate)
{
DATE* pDatTime = nullptr;
UINT uSize;
theApp.GetProfileBinary(_T("Options"), _T("BackupLastBackupDate"), pointer_cast<LPBYTE*>(&pDatTime), &uSize);
if (uSize == sizeof(DATE))
rBackupDate = *pDatTime;
else
rBackupDate = COleDateTime::GetCurrentTime();
delete[] pDatTime;
pDatTime = nullptr;
}
Code analysis gives me two warnings:
and
The latter warning suggests I use std::make_unique but since my pointer data is returned from the GetProfileBinary call, and given the statement in the related question, does that mean I should not use std::make_unique? I admit it is something I have not done before.
The useage of GetProfileBinary clearly states:
GetProfileBinary allocates a buffer and returns its address in *ppData. The caller is responsible for freeing the buffer using delete[].

pDateTime is supposed to be nullptr, and GetProfileBinary handles the allocation. Code Analysis mistakenly thinks you forgot the allocation.
It does need to check for success before calling delete[]. We can't use delete[]pDatTime because pDatTime is not an array. But GetProfileBinary allocates using new BYTE[size], so we need to cast back to BYTE.
You can also add a NULL check before reading pDatTime, that might make Code Analysis happy.
if (pDatTime && uSize == sizeof(DATE))
rBackupDate = *pDatTime;
else
rBackupDate = COleDateTime::GetCurrentTime();
if(pDatTime) delete[](BYTE*)pDatTime;
You can use std::unique_ptr<BYTE[]> cleanup((BYTE*)pDatTime) for deletion, but this has to be after GetProfileBinary is called.
Example:
DATE* pDatTime = nullptr;
GetProfileBinary(_T("Options"), _T("BackupLastBackupDate"), (LPBYTE*)(&pDatTime), &uSize);
std::unique_ptr<BYTE[]> cleanup((BYTE*)pDatTime); //automatic delete
if (pDatTime && uSize == sizeof(DATE))
rBackupDate = *pDatTime;
else
rBackupDate = COleDateTime::GetCurrentTime();
//pDatTime = NULL; <- Error when used with unique_ptr
...
//pDatTime is deleted later, when `cleanup` goes out of scope

Related

Dynamic allocation leaks memory?

bool CPythonNonPlayer::LoadNonPlayerData(const char *c_szFileName)
{
DWORD dwElements;
TMobTable *pTable = (TMobTable *) zObj.GetBuffer();
for(DWORD i = 0; i < dwElements; ++i, ++pTable)
{
TMobTable *pNonPlayerData = new TMobTable;
memcpy(pNonPlayerData, pTable, sizeof(TMobTable));
m_NonPlayerDataMap.insert(TNonPlayerDataMap::value_type(pNonPlayerData->dwVnum, pNonPlayerData));
}
return true;
}
My question is: what am I doing wrong? This leaks a lot of memory. After each call of this function, the application usage increases by 10MB.
The problem is not in this function. The problem is in the way you handle m_NonPlayerDataMap. This function transfers ownership of some objects to that map, and it's that map's responsibility to delete them when it's done with them. I'll bet it doesn't.
By the way, to avoid this kind of problem just don't do this. Don't use new unless you really need to. Instead, make the map a map of values rather than a map of pointers. If you can't figure out any way to make that happen, at least use smart pointers rather than raw pointers.
Use smart pointer wrappers to handle memory management for you, eg:
If using a version earlier than C++11:
#include <memory>
// std::auto_ptr is not container-safe!
typedef std::map<DWORD, TMobTable*> TNonPlayerDataMap;
TNonPlayerDataMap m_NonPlayerDataMap;
...
bool CPythonNonPlayer::LoadNonPlayerData(const char *c_szFileName)
{
DWORD dwElements = ...;
...
// I'm assuming this just returns a pointer to an existing memory
// buffer and is not actually allocating a new buffer. If it is,
// you need to free it when you are done copying it...
//
TMobTable *pTable = (TMobTable *) zObj.GetBuffer();
for(DWORD i = 0; i < dwElements; ++i, ++pTable)
{
std::auto_ptr<TMobTable> pNonPlayerData(new TMobTable);
// don't use memcpy! better would be to give TMobTable a copy constructor instead...
// std::auto_ptr<TMobTable> pNonPlayerData(new TMobTable(*pTable));
//
*pNonPlayerData = *pTable;
// if successful, release local ownership of the object.
// if failed, ownership will remain here and free the object when the auto_ptr goes out of scope.
//
if (m_NonPlayerDataMap.insert(std::make_pair(pNonPlayerData->dwVnum, pNonPlayerData.get())).second)
pNonPlayerData.release();
}
return true;
}
Alternatively, if you are using C++11 or later:
#include <memory>
// std::unique_ptr is container-safe!
typedef std::map<DWORD, std::unique_ptr<TMobTable>> TNonPlayerDataMap;
TNonPlayerDataMap m_NonPlayerDataMap;
...
bool CPythonNonPlayer::LoadNonPlayerData(const char *c_szFileName)
{
DWORD dwElements = ...;
...
// I'm assuming this just returns a pointer to an existing memory
// buffer and is not actually allocating a new buffer. If it is,
// you need to free it when you are done copying it...
//
TMobTable *pTable = (TMobTable *) zObj.GetBuffer();
for(DWORD i = 0; i < dwElements; ++i, ++pTable)
{
std::unique_ptr<TMobTable> pNonPlayerData(new TMobTable);
//
// or, if using C++14 or later:
// std::unique_ptr<TMobTable> pNonPlayerData = std::make_unique<TMobTable>();
// don't use memcpy! better would be to give TMobTable a copy constructor instead...
// std::unique_ptr<TMobTable> pNonPlayerData(new TMobTable(*pTable));
// std::unique_ptr<TMobTable> pNonPlayerData = std::make_unique<TMobTable>(*pTable);
//
*pNonPlayerData = *pTable;
// if successful, ownership of the object is transferred into the map.
// if failed, ownership will remain here and free the object when the unique_ptr goes out of scope.
//
m_NonPlayerDataMap.insert(std::make_pair(pNonPlayerData->dwVnum, std::move(pNonPlayerData)));
}
return true;
}

no need to delete struct memory in vector<StructA*>?

i saw some code like below, but i didn't see any delete statement, is there any memory leak problem?
struct RStatus
{
int fid;
int status;
};
void Foo()
{
vector<RStatus*> rsVec;
RStatus* rs = null;
rs = new RStatus(); // memory allocated here!
rs->fid = 0
rs->status = 0;
rsVec.push_back(rs);
}
If you use vector<RStatus*>, then you have to use delete, otherwise you will have a memory leak.
However, if you use vector<RStatus>, then you don't have to use delete — this is recommended1.
1. If you want to use pointers, then the recommendation is that you should be using smart pointers such as std::unique_ptr, or std::shared_ptr.
Yes, you should free your memory allocated :
struct RStatus
{
int fid;
int status;
};
void Foo()
{
vector<RStatus*> rsVec;
RStatus* rs = null;
rs = new RStatus(); // memory allocated here!
rs->fid = 0
rs->status = 0;
rsVec.push_back(rs);
// free :
unsigned int size = rsVec.size();
for (unsigned int i = 0; i < size; i++ )
delete rsVec[i]; // delete because you used new
}
If you don't do that, all the memory will never be released at the vector destruction.
I would suggest you to use std::vector<RStatus> instead of std::vector<RStatus*>.
You may also used smart ptr. You can found some documentation about it here : http://www.cplusplus.com/reference/memory/shared_ptr/
EDIT: As suggested in comments, if an exception is thrown at rsVec.push_back(rs), the memory allocated will be lost, that's why smart pointers would be a better solution. Or again, use std::vector<RStatus> instead.
Yes, there is a memory leak: the pointer to the created structure is lost after the vector is destroyed, and the memory is never released.
Unless someone performs a delete for each element of rsVec before clearing or destroying the vector.
Yes, that code leaks the RStatus.
It also does nothing else: possibly the real code's vector gets passed to some function that takes posession of the vector's contents.
Tracking down memory leaks is generally not a local problem: every use of that pointer has to, in theory, be examine to figure out if it leaks. Techniques like 'if I allocate it, delete it' and RAII (including smart pointers) attempt to make it more local, so you can tell from an incomplete program if there is a leak.
use boost::shared_ptr if you don't want to bother yourself with a deletion of allocated objects.
http://www.boost.org/doc/libs/1_54_0/libs/smart_ptr/shared_ptr.htm
struct RStatus
{
int fid;
int status;
};
void Foo()
{
vector<shared_ptr<RStatus> > rsVec;
shared_ptr<RStatus> rs = shared_ptr<RStatus>(); // empty shared_ptr
rs.reset(new RStatus()); // memory allocated here!
rs->fid = 0
rs->status = 0;
rsVec.push_back(rs); // shared_ptr is copied
}// vector is destroyed and shared_ptrs also
be careful however not to mixed up things using both shared_ptr and ordinary, raw pointers to avoid situation when shared_ptr tries to delete object which is already deleted

how to free memory after ASSERT_TRUE in gtest

I have use case scenario.
List* pList = new List();
for (...)
{
Integer* pInt = new Integer();
ASSERT_TRUE(pInt != NULL);
pList->Add(*pInt);
}
Now, should pInt be null in any of iteration, then this test case will stop and pList will not be freed.
Is there any way to free up pList when ASSERT_TRUE executes?
Thanks
If you can use lambdas, you could do:
ASSERT_TRUE(pInt != nullptr)
<< [pList]()->std::string { delete pList; return "Your error message."; }();
The lambda is only executed if the assertion fails.
However, the best option is probably to use a std::unique_ptr or similar smart pointer rather than raw pointers and avoid the worry altogether.
Now, should pInt be null in any of iteration, then this test case will stop and pList will not be freed.
Assuming you didn't override the new operator (if you did, you probably wouldn't be asking about this), and assuming your compiler is not buggy, pInt will never be null. On failure, new throws a std::bad_alloc exception, it doesn't return null.
Moreover, assertions are for things that should always hold (as is the case), no matter what. An assertion failure is a bug. There's no point in adding code to clean up after an assertion failure: just fix the bug instead.
Now to the freeing... The sample code provided can just forget new and use automatic objects:
List pList;
for (...)
{
Integer pInt = Integer();
pList.Add(pInt);
}

Does deleting copied pointers to differing pointer types cause a memory leak?

I've narrowed down in my application that my AVI video player is leaking memory. I have the following code:
...
LPBYTE pChunk = new BYTE[lSize];
if(!pChunk)
return false;
hr = AVIStreamReadFormat(pStream, AVIStreamStart(pStream), pChunk, &lSize);
if(hr)
{
delete [] pChunk;
return false;
}
m_pVideoFormats[i] = (LPBITMAPINFO)pChunk;
Later on when it comes time to remove the video, I simply just delete:
if(m_pVideoFormats[i])
delete [] ((LPBYTE)m_pVideoFormats[i]);
Will this cause a memory leak because of how I'm casting this pointer around? Thanks!
No, that won't leak. It doesn't matter how you cast it around, the important thing is that you delete the same type you allocated. You've matched BYTE[] to BYTE[], so that's not your problem.
Your code doesn't leak memory, but you're doing some unnecessary things.
Checking for nullptr after new is pointless since std::bad_alloc is thrown instead of a nullptr being returned if allocation fails.
Similarly, checking for nullptr before delete is unnecessary since delete [] nullptr is perfectly valid.
Also, use smart pointers instead of managing pointers to raw chunks of memory.
std::unique_ptr<BYTE[]> pChunk;
try {
pChunk.reset( new BYTE[lSize] );
} catch( const std::bad_alloc& ) {
return false;
}
hr = AVIStreamReadFormat(pStream, AVIStreamStart(pStream), pChunk, &lSize);
if(hr)
{
// delete [] pChunk; // not needed - smart pointer will free memory
return false;
}
m_pVideoFormats[i] = (LPBITMAPINFO)pChunk.release();
...
delete [] ((LPBYTE)m_pVideoFormats[i]);
m_pVideoFormats[i] = nullptr; // set to nullptr to avoid double deletion

Custom Memory Manager

I am trying to implement a custom memory manager and I am wondering if there is a better way to implement this function, as when I am asked about void pointer arithmetic, several people thought that if I had a void* in C++, something was very wrong.
// allocates a page of memory.
void ObjectAllocator::allocatePage()
{
//if(OAStats_.PagesInUse_ >= Config_.MaxPages_)
//throw exception
void* buffer = ::operator new(OAStats_.PageSize_); // allocate memory, no constructor call.
// =============== Setup the PageList_ ===============
GenericObject* pNewNode = ::new(buffer) GenericObject(); // Construct GenericObject for the pagelist.
pNewNode->Next = PageList_->Next; // pNewNode points to wherever PageList_ pointed to.
PageList_->Next = pNewNode; // PageList_ points to pNewNode
pNewNode = NULL; // dont need this handle anymore
buffer = static_cast<char*>(buffer) + sizeof(GenericObject); // move pointer to point after the generic object.
// =============== Setup the FreeList_ ===============
for(int i=0;i<Config_.ObjectsPerPage_;++i)
{
static GenericObject* pPreviousNode = NULL; // static variable to hold the previous node
pNewNode = ::new(buffer) GenericObject(); // Construct GenericObject for the freelist.
pNewNode->Next = pPreviousNode;
pPreviousNode = pNewNode;
buffer = static_cast<char*>(buffer) + OAStats_.ObjectSize_; // move pointer by ObjectSize.
++OAStats_.FreeObjects_;
}
FreeList_->Next = pNewNode;
++OAStats_.PagesInUse_;
++OAStats_.Allocations_;
}
If you need a block of memory for for storing a string (8-bit ANSI), it makes sense to declare a pointer to that buffer as char and operate on it.
In your case, you need a block of memory that is a 'blob', it has no inherent type, so you correctly chose void* to represent that blob.
Now you need to increment that pointer by the size of some object. You cannot perform arithmetic on a void pointer for obvious reasons, so what do you do? Cast it. There is no shame in that.
In C++, on raw bytes, use a char*, and don't think any less of yourself. It's The Right Thing To Do (tm). Especially if you wrap it in a higher level construct, like you have.
There's nothing inherently wrong with the void*. However, what we often see is people coming from C who overuse void* when they should do something else. If you're managing raw memory blobs, then a void* is perfectly appropriate. However, there's rarely any other reason to do it.