From CString to char*, ReleaseBuffer() must be used after GetBuffer(). But why? What will happen if I don't use ReleaseBuffer() after GetBuffer()?
Can somebody show me an example? Thanks.
I'm not sure that this will cause a memory leak, but you must call ReleaseBuffer to ensure that the private members of CString are updated. For example, ReleaseBuffer will update the length field of the CString by looking for the terminating null character.
What will happen if I don't use ReleaseBuffer() after GetBuffer()?
I haven't used MFC (and hopefully won't ever have to touch it with a ten-foot pole) but, as a rule of thumb, whenever you have an API that has both GetXXX() and ReleaseXXX() (especially when the result of GetXXX() conveniently is of the type that ReleaseXXX() takes) -- then when you forget to call ReleaseXXX() for every one of your GetXXX() calls, you will leak an XXX.
Here's an example of how I used CString::GetBuffer() and CString::ReleaseBuffer() :
LPTSTR pUnitBuffer = pAPBElement->m_strUnits.GetBuffer(APB_UNIT_SIZE);
if (pUnitBuffer != "")
{
if (strncmp(pAPBElement->m_strUnits, (char*)pszBuffer[nLoop - nFirst], APB_UNIT_SIZE) != 0)
{
LPTSTR pUnitOriginal = pAPBElement->m_strOriginal.GetBuffer(APB_UNIT_SIZE);
strncpy(pUnitBuffer,
(char*)&pszBuffer[nLoop - nFirst],
APB_UNIT_SIZE);
strncpy(pUnitOriginal,
(char*)&pszBuffer[nLoop - nFirst],
APB_UNIT_SIZE);
pAPBElement->m_strOriginal.ReleaseBuffer();
}
}
pAPBElement->m_strUnits.ReleaseBuffer();
If you do not modify the contents of the CString using the pointer obtained using GetBuffer(), you do NOT need to call ReleaseBuffer() afterwards
Related
what is the difference of pointers between and which is better in terms of memory management
void Loo(){
Song* pSong = new Song(…);
//…
string s = pSong->duration;
}
and
void Hoo(){
unique_ptr<Song> song2(new Song(…));
//…
string s = song2->duration;
}
In the first case you need to call delete yourself and make sure it happens on all program control paths.
That is easier said than done. It's tempting to write delete pSong; just before the closing brace of the function and be done with it. But what happens, say, if string s = song2->duration throws an exception? (Yes it's possible; for example if song2->duration is a type that has a conversion operator defined so it can be assigned to a string.)
With std::unique_ptr, delete will be called for you when it goes out of scope.
Although in this particular case Song song(...); may be more appropriate.
Here is what is going on. When I try and run an AfxMessageBox from my CDialog extension class, I get an errror (see below). I've googled the internet but come up short. This is the only place the messagebox fails, and I know the rest of the code works (I stepped through it).
Does anyone know how to fix this?
Thanks in advance!
Error message when AFXMESSAGEBOX opens:
Unhandled exception at 0x014b4b70 in IsoPro.exe: 0xC0000005: Access violation reading location 0x34333345.
Code to launch AfxMessageBox, from within CDialog
LPTSTR temp;
mainPassword.GetWindowText((LPTSTR)temp,100);
CString cstr;
cstr.Format("mainPassword = %s",temp);
AfxMessageBox(cstr);
Code to display CDialog:
CEnterpriseManagementDialog* emd = new CEnterpriseManagementDialog();
emd->Create(IDD_ENTERPRISE_MANAGEMENT_DIALOG);
emd->ShowWindow(SW_SHOW);
The problem is how you use GetWindowText:
LPTSTR temp;
mainPassword.GetWindowText((LPTSTR)temp,100);
You are letting GetWindowText attempt to write to some unallocated memory passing the uninitialized temp pointer. If you really want to use a raw output buffer, you should allocate room for it before passing a pointer to GetWindowText, e.g.:
TCHAR temp[100];
mainPassword.GetWindowText(temp, _countof(temp));
// NOTE: No need to LPTSTR-cast
But, since you are using C++, you may want to just use a string class like CString, instead of raw buffers, e.g.:
CString password;
mainPassword.GetWindowText(password);
CString msg;
msg.Format(_T("mainPassword = %s"), password.GetString());
// or you can just concatenate CStrings using operator+ ...
AfxMessageBox(msg);
It looks like the variable temp is an uninitialized pointer (the definition of LPTSTR is a char *).
Try defining temp as an array instead:
TCHAR temp[64];
I'm writing C++ dll on Visual studio 2013. My dll should read parameters from ini file. So, I've created a function for this purpose (ReadConnectionSettings()). My static variable serverIP gets value properly during the function working, however once the function complete running the variable (serverIP) loses its value. What seems to be the problem?
static LPTSTR serverIP = _TEXT("");
void ReadConnectionSettings()
{
TCHAR url[256];
GetPrivateProfileString(_T("Connection"), _T("Url"), _T(""), url, 256, NameOfIniFile);
serverIP = url;
}
You are pointing the pointer serverIP at stack memory url.
This goes out of scope when the function exits, so your pointer is left pointing to junk.
What you could do is make serverIP a buffer instead, and copy the URL into it. Then it would persist.
That is:
static TCHAR serverIP[256] = _TEXT("");
Then:
_tcsnccpy(serverIP, url, 255);
Or as #DavidOtano suggested, you could keep your existing serverIP pointer, and use:
serverIP = _tcsdup(url);
But if you do this, you're dynamically allocating memory, so will need to remember to call:
free(serverIP);
when you no longer need it, to avoid a memory leak.
You're setting the static pointer variable to point at a local variable that does not exist anymore after the function has returned.
A good way to return a string from a function in a Windows program, is to return a std::wstring.
Try that.
Regarding LPTSTR and _TEXT, you only need this if you intend to support MFC in DLLs in Windows 9x. Is that the case? If not, just ditch that Microsoft silliness.
The code fixed according to above advice (off the cuff, untouched by compiler's hands):
auto connection_settings()
-> std::wstring
{
std::wstring url( 256, L'#' );
auto const n = GetPrivateProfileString( L"Connection", L"Url", L"", &url[0], url.size(), NameOfIniFile );
url.resize( n );
return url;
}
One nice property of this code is that it no longer modifies a global variable.
EDIT: Dear Future Readers, the std::string had nothing to do with the problem. It was an unterminated array.
In a nutshell, the problem is that adding a declaration of a single std::string to a program that otherwise contains only C causes the error "Access violation reading location 0xfffffffffffffffe."
In the code below, if the line where the std::string is declared is commented out, the program runs to completion without error. If the line however is left in the program (uncommented), the program crashes with the above stated Acess Violation error. When I open the running program in the VS2010 debugger, the Access Violation has occurred at the call to ldap_search_sA().
Notice that the declared std::string is never used. It doesn't have to be used for it to cause the access violation. Simply declaring it will cause the Access Violation.
My suspicion is it has nothing to do with the LDAP code, but I could be wrong.
int main()
{
try {
// Uncommenting the next line causes an Access Violation
// at the call to ldap_search_sA().
// std::string s;
LDAP* pLdapConnection = ldap_initA("eu.scor.local", LDAP_PORT);
ULONG version = LDAP_VERSION3;
ldap_set_option(pLdapConnection, LDAP_OPT_PROTOCOL_VERSION, (void*) &version);
ldap_connect(pLdapConnection, NULL);
ldap_bind_sA(pLdapConnection, NULL, NULL, LDAP_AUTH_NTLM);
LDAPMessage* pSearchResult;
PCHAR pMyAttributes[2];
pMyAttributes[0] = "cn";
pMyAttributes[1] = "description";
ldap_search_sA(pLdapConnection, "dc=eu,dc=scor,dc=local", LDAP_SCOPE_SUBTREE, "objectClass=computer)", pMyAttributes, 0, &pSearchResult);
} catch (...) {
printf("exception\n");
}
return 0;
}
PCHAR pMyAttributes[2];
pMyAttributes[0] = "cn";
pMyAttributes[1] = "description";
Attribute array should be NULL-terminated:
PCHAR pMyAttributes[3];
pMyAttributes[0] = "cn";
pMyAttributes[1] = "description";
pMyAttributes[2] = NULL;
I don't know what ldap_search_sA is, but the ldap_search function in
OpenLDAP takes a pointer to a null pointer terminated array of char*.
The array you are passing isn't correctly terminated, so anything may
happen. I'd recommend using std::vector<char*> for this, in general,
and wrapping the calls in a C++ function which systematically postfixes
the terminator, so you don't forget. Although in such simple cases:
char* attributes[] = { "cn", "description", NULL };
will do the trick. It will probably provoke a warning; it really should
be:
char const* attributes[] = { ... };
But the OpenLDAP interface is legacy C, which ignores const, so you'd
need a const_cast at the call site. (Another argument for wrapping
the function.)
Finally, I'd strongly advise that you drop the obfuscating typedefs
like PCHAR; they just make the code less clear.
According to my experience, when weird things like this are observed in C++, what is in fact happening is that some piece of code somewhere corrupts memory, and this corruption may manifest itself in various odd ways, including the possibility that it may not manifest itself at all. These manifestations vary depending on where things are located in memory, so the introduction of a new variable probably causes things to be moved in memory just enough so as to cause a manifestation of the corruption where otherwise it would not be manifested. So, if I were in your shoes I would entirely forget about the string itself and I would concentrate on the rest of the code, trying to figure out exactly what you do in there which corrupts memory.
I notice that you invoke several functions without checking their return values, even though it is not in the spec of these functions to throw exceptions. So, if any of these functions fails, (starting with ldap_initA,) and you proceed assuming that it did not fail, you may get memory corruption. Have you checked this?
I have a very simple class that looks as follows:
class CHeader
{
public:
CHeader();
~CHeader();
void SetCommand( const unsigned char cmd );
void SetFlag( const unsigned char flag );
public:
unsigned char iHeader[32];
};
void CHeader::SetCommand( const unsigned char cmd )
{
iHeader[0] = cmd;
}
void CHeader::SetFlag( const unsigned char flag )
{
iHeader[1] = flag;
}
Then, I have a method which takes a pointer to CHeader as input and looks
as follows:
void updateHeader(CHeader *Hdr)
{
unsigned char cmd = 'A';
unsigned char flag = 'B';
Hdr->SetCommand(cmd);
Hdr->SetFlag(flag);
...
}
Basically, this method simply sets some array values to a certain value.
Afterwards, I create then a pointer to an object of class CHeader and pass it to
the updateHeader function:
CHeader* hdr = new CHeader();
updateHeader(hdr);
In doing this, the program crashes as soon as it executes the Hdr->SetCommand(cmd)
line. Anyone sees the problem, any input would be really appreciated
When you run into a crash, act like a crime investigator: investigate the crime scene.
what is the information you get from your environment (access violation? any debug messages? what does the memory at *Hdr look like? ...)
Is the passed-in Hdr pointer valid?
Then use logical deduction, e.g.:
the dereferencing of Hdr causes an access violation
=> passed in Hdr points to invalid memory
=> either memory wasn't valid to start with (wrong pointer passed in), or memory was invalidated (object was deleted before passing in the pointer, or someone painted over the memory)
...
It's probably SEGFAULTing. Check the pointers.
After
your adding some source code
your comment that the thing runs on another machine
the fact that you use the term 'flag' and 'cmd' and some very small datatypes
making me assume the target machine is quite limited in capacity, I suggest testing the result of the new CHeader for validity: if the system runs out of resources, the resulting pointer will not refer to valid memory.
There is nothing wrong with the code you've provided.
Are you sure the pointer you've created is the same same address once you enter the 'updateHeader' function? Just to be sure, after new() note the address, fill the memory, sizeof(CHeader), with something you know is unique like 0XDEAD, then trace into the updateHeader function, making sure everything is equal.
Other than that, I wonder if it is an alignment issues. I know you're using 8 bit values, but try changing your array to unsigned ints or longs and see if you get the same issue. What architecture are you running this on?
Your code looks fine. The only potential issue I can see is that you have declared a CHeader constructor and destructor in your class, but do not show the implementation of either. I guess you have just omitted to show these, else the linker should have complained (if I duplicate this project in VC++6 it comes up with an 'unresolved external' error for the constructor. It should also have shown the same error for the destructor if you had a... delete hdr; ...statement in your code).
But it is actually not necessary to have an implementation for every method declared in a class unless the methods are actually going to get called (any unimplemented methods are simply ignored by the compiler/linker if never called). Of course, in the case of an object one of the constructor(s) has to be called when the object is instantiated - which is the reason the compiler will create a default constructor for you if you omit to add any constructors to your class. But it will be a serious error for your compiler to compile/link the above code without the implementation of your declared constructor, so I will really be surprised if this is the reason for your problem.
But the symptoms you describe definitely sounds like the 'hdr' pointer you are passing to the updateHeader function is invalid. The reason being that the 1st time you are dereferencing this pointer after the updateHeader function call is in the... Hdr->SetCommand(cmd); ...call (which you say crashes).
I can only think of 2 possible scenarios for this invalid pointer:
a.) You have some problem with your heap and the allocation of memory with the 'new' operator failed on creation of the 'hdr' object. Maybe you have insufficient heap space. On some embedded environments you may also need to provide 'custom' versions of the 'new' and 'delete' operator. The easiest way to check this (and you should always do) is to check the validity of the pointer after the allocation:
CHeader* hdr = new CHeader();
if(hdr) {
updateHeader(hdr);
}
else
//handle or throw exception...
The normal behaviour when 'new' fails should actually be to throw an exception - so the following code will cater for that as well:
try{
CHeader* hdr = new CHeader();
} catch(...) {
//handle or throw specific exception i.e. AfxThrowMemoryException() for MFC
}
if(hdr) {
updateHeader(hdr);
}
else
//handle or throw exception...
}
b.) You are using some older (possibly 16 bit and/or embedded) environment, where you may need to use a FAR pointer (which includes the SEGMENT address) for objects created on the heap.
I suspect that you will need to provide more details of your environment plus compiler to get any useful feedback on this problem.