|
|
> does having a static member mean i can only have one instance of my class in the program?
No, but it does have the effect of making all classes share the same member (in the case of a variable) and freeing it from the clutches of the class vtable (in the case of a function).
Basically, you're dealing with a language that has no built in threading support, so you need to ask the OS for it, and the OS is in C, and C only understands static ('global') functions in this context - you'll find you need to do the same thing if you want to pass a member function to something like EnumWindows as a callback procedure.
One other important note is that static member functions can't access non-static member vars, so if your thread proc needs to access some other members, you can pass a pointer to the class (e.g. this ) as a/the parameter to the threadproc function, then access members (with appropriate access locks) through this.
I think multi-threaded apps can give us some of the most difficult to manage code bases of all modern cs concepts. It can be very difficult to get right.
|
|
|
|
|
can someone suggest me how to go about making the Multiline list control using embeddedVC++. The regular method for desktop using VC++ just doesn't work anyhow in none of the ways.....
|
|
|
|
|
I have two property sheets that need to share a common set of CPropertypage(s) but I need the titles to change dependant on the parent CPropertypage. If I call SetWizardMode() any subsequent calls to SetTitle have no effect. Any ideas how to get around this?
Confused Programmer!
|
|
|
|
|
Hi.
Try to get parent frame (i'll called it pFrame) of each PropertySheet then type:
pFrame->SetTitle(lpszTitle);
pFrame->SetWindowText(lpszTitle);
I've notice that when you use SetTitle, the title is effectivly modify but on resize.
Use CWnd::SetWindowText to modify directly the title, but if you forgot to call SetTitle, then
on resize the title will restore to the previous name that why you should call two methods.
Unknown.
|
|
|
|
|
Thanks, but I'm just as confused......
I've added the following to the ::OnSetActive event of one of my pages:
CPropertySheet* pParent = (CPropertySheet*)GetParent();
CFrameWnd* pFrame1 = pParent->GetParentFrame();
CFrameWnd* pFrame2 = pParent->GetTopLevelFrame();
Both of the frame vars are null, I'm obviously missing my way to the parent frame! Can you advise?
Still Confused Programmer!
|
|
|
|
|
Once you're in wizard mode your property sheet will use the title of the current page as its title, so you need to change the title of the property pages themselves:
CTabCtrl* pTab = ((CPropertySheet*)GetParent())->GetTabControl(); //This assumes this code is in one of the pages
ASSERT (pTab);
TC_ITEM ti;
ti.mask = TCIF_TEXT;
ti.pszText = szTitleYouWant;
VERIFY (pTab->SetItem (nPageIndex, &ti));
|
|
|
|
|
Brilliant! - This works a treat, thanks.
|
|
|
|
|
Anyone know a good report writer tool with graphic editor and source code
for VC++??
Tanks
DL
|
|
|
|
|
Environment: VC++ 6.0, Windows NT 4.0
I'm trying to write a app that talks to a database
via Embedded SQL statements. The app is designed to run
continuously, looping through a small amount of code.
The Problem is that while generating the SQL statements,
memory is leaked by Constant Assigned Strings.
eg. CString fred = "fred";
The following code written to check memory usage:
void CTestSQLStringDlg::OnButton1() {
while(1) {
CMemoryState m1, m2, mdiff;
m1.Checkpoint();
fred();
m2.Checkpoint();
mdiff.Difference(m1, m2);
mdiff.DumpStatistics();
TRACE("\n");
}
}
void CTestSQLStringDlg::fred(){
CString string ="hello";
}
The Results (irrelevant data removed) were, after two loops:
mdiff - Total allocations: 18 bytes.
m1 - Total allocations: 7240 bytes.
mdiff - Total allocations: 18 bytes.
m1 - Total allocations: 7258 bytes.
As can be seen, each time through the loop, the Total Memory Allocations
increases by 18 bytes.
If a global CString is used, there is no memory leak ie:
CString str = "hello";
void CTestSQLStringDlg::fred(){
CString string =str;
}
Although I can use this workaround, it is very impractical to Globally
declare all of the constant strings I need.
I would like to know why this memory leak occurs or an alternate
practical work around??
Thanks
Simon
|
|
|
|
|
Simon,
Are you sure that a) the memory is truly leaking, and b) it is coming from the static CString? (I have trouble believing that CString, one of the most popular members of the MFC library, would leak memory. Also consider that CString uses reference counting; seperate CString objects set to the same static data always point to the same m_pchData, until one or the other is changed).
I suspect that what you're witnessing is a false memory leak; either that, or code in other parts of fred() is leaking memory. Using CMemoryStatus::DumpAllObjectsSince() shows no leaks when a static CString is alloted in fred(); perhaps using that function might better point out the exact location of any leaks which might exist.
Walter Gildersleeve
Freiburg, Germany
walter.gildersleeve@pe-gmbh.de
|
|
|
|
|
I agree with Walter. I set up a test with this code:
<br />
class CTestSQLStringDlg<br />
{<br />
public:<br />
void fred();<br />
void OnButton1();<br />
};<br />
<br />
void CTestSQLStringDlg::fred()<br />
{<br />
CString string ="hello";<br />
}<br />
<br />
void CTestSQLStringDlg::OnButton1() <br />
{<br />
int i=0;<br />
while(i<10) <br />
{<br />
CMemoryState m1, m2, mdiff;<br />
m1.Checkpoint();<br />
fred();<br />
m2.Checkpoint();<br />
mdiff.Difference(m1, m2);<br />
mdiff.DumpStatistics();<br />
TRACE("\n");<br />
++i;<br />
}<br />
<br />
}<br />
<br />
void main(int argc, char* argv[])<br />
{<br />
CTestSQLStringDlg ts;<br />
ts.OnButton1();<br />
}
I get no leak.
CString is the most popular MFC class, I really doubt that it is leaking, because if it were then almost no MFC apps would work for long.
Jim
|
|
|
|
|
Well,
CString is not the greatest thing since the sliced bread
"When CString::ReleaseBuffer is called and the length of
the string is less than the allocated buffer length,
the extra bytes are not released.
This just means that your program might end up maintaining more memory than absolutely necessary.
This will not cause a memory leak.
All of the memory will be freed when the CString object is destroyed."
This was the case for version 4.0 and earlier versions of VC.
I don't know if this is reaccuring in VC 6.0 .
It would be intersting though.
Cheers
Alfadhly
|
|
|
|
|
<RANT>
That particular bug is fixed in VC 6.0, but you can certainly cause problems by directly writing to the CString internal buffer. A "Releasebuffer" call just sends chills up my spine. I'd rather you use a few dozen goto's than write into the CString buffer.
As I pointed in another post here a couple of days ago, I've been writing MFC code since 1994 and have never directly changed a CString internal buffer. There is never a good reason to do this. Not ever. Not even once. I never told any one to lie. Using the evil GetBuffer/ReleaseBuffer members combines the worst features of C++ and C. I'm not against a nonmodifable pointer to the buffer ( like STL's c_str() ), but casting away the constness of the buffer is worse than murder.
I think that it is evil to muck about with the internal buffer of a string object. If you want to diddle with a buffer then make a proper buffer and party on. The fact that CString GetBuffer/ReleaseBuffer tempts you unzip it's pants and reach inside is the major reason that CString is not as good as sliced bread.
</RANT>
Jim
|
|
|
|
|
lol,
Sometimes it too scary to question the authorities, isn't?
Mike and his team recomended, posted it as a sample work around. So there.
Personally , I will use it when I use goto... but perhaps _asm is better
And don't shoot the masenger.
Cheers
Alfadhly
|
|
|
|
|
I really don't understand what you problem is with GetBuffer/ReleaseBuffer.
The reason you don't want to mess with the internal buffer is because you confuse CStrings internal state. GetBuffer/ReleaseBuffer provide a mechanism in which the internal state will stay correct.
There is no other reason to not use the internal buffer, and there is no difference between using CStrings buffer and allocating one yourself on the heap, except that if you need to copy the data into a CString anyways, you save the hassle of an extra copy.
GetBuffer/ReleaseBuffer were designed to be used this way, why not take advantage of it?
|
|
|
|
|
When I started with VC there was the known bug mentioned above. Even though that bug has been fixed, I still consider GetBuffer/ReleaseBuffer to be evil.
The reason is because they violate what seem to me to be good object oriented design critera.
I think that an object ought to manage its own interal state. But if you call "GetBuffer" then you have to keep this in mind:
"If you use the pointer returned by GetBuffer to change the string contents, you must call ReleaseBuffer before using any other CString member functions. ... Note that if you keep track of the string length yourself, you should not append the terminating null character. You must, however, specify the final string length when you release the buffer with ReleaseBuffer. If you do append a terminating null character, you should pass –1 for the length to ReleaseBuffer and ReleaseBuffer will perform a strlen on the buffer to determine its length. "
Please gag me with a spoon. The way I read this is as follows: "If you call Getbuffer then we will lay these mines around. Try not to step on them."
Call GetBuffer and instead of having a nice solid string object that can take care of itself, you now have to stop thinking about the problem you are trying to solve and start thinking about your string object causeing a catastrophe. Let's see now, am I sure there will be null at the end? And what is the lenght of my string now? I wrote it down on a postit note somewhere, where did I put it? Why kid yourself using a string class at all if you are going to track the null character and the length yourself? Wouldn't it be more honest to just directly instantiate a buffer and use standard 'C' on it? At least then everyone seeing the code would know that you don't mind living on the edge.
It just seems to me that there would be fewer errors in the world if CString did not allow direct write access to its buffer. CString has all the members you need to make the string grow, shrink, jump, and dance all you want without worrying. Why not use them?
Now please me excuse while I write an expose on the "goto" statement.
Jim
|
|
|
|
|
After writing the above rant, I pulled out my battered copy of Mike Blaszczak's seminal book "MFC 4 Programming with Visual C++" and looked up his discussion of GetBuffer/Release buffer.
He starts with a horrendous example:
<br />
CString str;<br />
LPTSTR pChars = str.GetBuffer(0);
strcpy(pChars, _T("Hockey"));<br />
He points out in the following text that this kind of code can get you fired.
Then he provides an even more blood chilling example under the heading of "improving efficiency with Releasebuffer()". At least the above example blows up as soon as you touch it. This example actually "works" and is the perfect illustration of how fast down the slippery slope of evil an innocent programmer might slide if he or she partakes even a bite of the GetBuffer apple:
<br />
CString str;<br />
LPTSTR pWork;<br />
int nCount;<br />
<br />
<br />
pWork = str.GetBuffer(16384);<br />
for(nCount =0; ncount <16384; nCount++)<br />
{<br />
*pWork++ = _T('x'); <br />
}<br />
str.ReleaseBuffer(16384);
Of course he could have just said
CString str(_T('x'),16384); but what fun would that be?
I have to admit I my faith in MikeB was severely shaken by this example, but after taking a nitro pill and allow some time for my hands to stop shaking I continued reading his discussion. After a discussion of the Bad Things that can happen if you screw up the CString buffer, MikeB redeems himself by saying just what I was saying, only he says it a lot better than me:
"The most efficient approach to string intensive work with MFC involves using CString objects to hold your strings. Whenever you need to dynamically construct strings, particularly when you are concatenating them together your best bet is build the string with regular character arrays or dynamically allocated buffers before turning those arrays over to a CString object for safe keeping. (emphasis added)
MikeB, an MFC Deity, has spoken! Who are we mere mortals to contradict him!
It's a slow day at work today, in case you hadn't guessed that already.
|
|
|
|
|
But that's just it, the pointer returned by GetBuffer *IS* a "regular character array".
I also fail to see what's wrong with his example, other than it's complexity. The code correctly works in either UNICODE or ANSI and correctly sizes the string in ReleaseBuffer.
You keep saying how something is bad without proving any real data to back it up, other than your opinion. Show me an example of how this is dangerous (at least more dangerous than using a seperate buffer).
|
|
|
|
|
I just think that mixing 'C' style buffer manipulation with C++ objects is very dangerous from a reliablity and maintainiblity point of view.
I've done a fair amount of maintenace coding, and this experience makes me see Getbuffer as an ugly hack that combines the worst elements of C and C++. The horrific example from MikeB's book shows you how ugly and dangerous GetBuffer can be. What did his use of CString in that second example do except obstafcate? If somewhere along the way the external buffer count got messed up, or releasebuffer was called with void parameters then you have created a debugging nightmare.
I think MikeB's advice to use standard buffers (if you need ultimate efficency) and then save them in CString is correct. It's an opinion and we all have them.
Jim
|
|
|
|
|
> You keep saying how something is bad without proving any real data
> to back it up, other than your opinion. Show me an example of how
> this is dangerous (at least more dangerous than using a seperate buffer).
Hmmm... How about trying to *think* about potential dangers, before jumping on the keyboard to counterattack? Watch, I will demonstrate:
Think (try it)... How about because you now have more places to screw up, esp. with less experienced coders:
o Should I call GetBuffer() or GetBufferSetLength()? Potential screwup #1.
o The call to GetBuffer()/GetBufferSetLength() : when using char/TCHAR arrays, most people are used to including space for the NUL terminator. You do not have to specify NULs most of the time when using string objects. Potential screwup #2.
o The call to ReleaseBuffer() : did you place a NUL in there, and/or did you specify the length of the new string in the call to ReleaseBuffer()? Are there embedded NULs? (After all, you asked for a BUFFER, not a STRING BUFFER.) Potential screwup #3.
o Walking off a local buffer can usually be quickly detected in debug builds. It might be more difficult to see if you stepped on either a CString's internal state, or a CStringData's internal state. Potential screwup #4.
o People that do not know any better will store the pointer returned by GetBuffer()/GetBufferSetLength(). Local buffers tend not to change their location/address. Potential screwup #5
Another general issue:
o Using any string object (that uses dynamically allocated memory) is slower than using local buffers. That is VERY IMPORTANT when dealing with multiple-CPU systems, and running into heap contention.
BTW:
> I think MikeB's advice to use standard buffers (if you need ultimate
> efficency) and then save them in CString is correct. It's an opinion
> and we all have them.
No, obtaining and using a local buffer *IS* faster (moving your stack pointer) than using a string object that dynamically allocates its memory. Welcome to the world of facts!
Peace!
-=- James.
|
|
|
|
|
None of what you claim is any more dangerous than calling new and delete to create dynamic memory.
While you're right about stack variables, I'm not talking about them. I'm talking about dynamically allocated memory. For instance, when reading a registry entry, you don't know how much space you need ahead of time, so you have to dynamicly allocate. Or when you need to read a 10 MB file into a string.
You'd rather allocate memory, load the data into the allocated memory, then copy it into a string, then delete the original memory? Talk about inefficiency. It's much quicker, faster, and cleaner to just get a buffer of the right length, read the data into it, then release the buffer at the correct size.
It takes about 1/3 of the code, and is 4x faster.
All the things you mention about embedded NULL's are things you have to worry about with local buffers as well. Your arguments just don't make sense.
|
|
|
|
|
> None of what you claim is any more dangerous than calling
> new and delete to create dynamic memory.
(As an example...) Fifth bullet point: storage of the returned pointer. When you allocate via "new", the returned pointer tends to be valid until the call to delete. It can be stored, copied, read from, written to, all without the pointer becoming invalid. The same is not true with the pointer returned from GetBuffer(). That pointer is likely to become invalid after any action is performed on the CString object. That is documented... You *did* read the documents, yes? So you should know of that difference.
> For instance, when reading a registry entry, you don't
> know how much space you need ahead of time
No, but you damn well better have a good idea, or you did not think things through enough. You should know that you will be reading between 0 and 8192 bytes of data, and locally allocate enough for that much data. (Being dumb enough to store large amounts of data in the Registry is another problem.)
> Or when you need to read a 10 MB file into a string. You'd rather
> allocate memory, load the data into the allocated memory, then
> copy it into a string, then delete the original memory?
> Talk about inefficiency.
No, I would rather allocate the memory once, and HOLD ON TO IT, rather than pass a string object around. Passing a string object around is inefficient. String objects contain overhead that you might not need. Besides, am I sure that the file contains only text data?
> It's much quicker, faster, and cleaner to just get a buffer of the
> right length, read the data into it, then release the buffer at the
> correct size. It takes about 1/3 of the code, and is 4x faster.
1/3 of the code compared to what? Have you examined the internals of CString's implementation, and its reference counting code? That idea is similar to people using printf() to write out a static string and thinking that it is "just one line of code" without looking into what printf() is doing internally. Also, you still end up with the potential problem of passing the string object around, where passing the pointer would be quicker (with no overhead).
> All the things you mention about embedded NULL's are things
> you have to worry about with local buffers as well.
I did not talk about embedded NULLs, I was talking about embedded NULs (you DO know the difference, yes?). And besides, looking at the second bullet point, the point I was trying to make was that when you create a local buffer for storing strings, you (should) know enough to include the terminating NUL character at the end of the string. When dealing with the pointer returned from GetBuffer(), is this always the case?
Also, you do not find any use in the ability to quickly detect buffer overruns in debug builds by using local buffers?
> Your arguments just don't make sense.
Read them again. Eventually, you will get it.
-=- James.
|
|
|
|
|
The GetBuffer() pointer is valid until you call ReleaseBuffer. Period. Same as a new'd data is valid until you call delete (or delete []). It's the same concept.
As long as you don't call ReleaseBuffer, the pointer can be stored, copied, read from, written to, all without the buffer becoming invalid. *JUST LIKE A NEW'D POINTER*
And just like a new'd pointer, you have to be careful that you or another thread doesn't delete it before you're done with it, so you can't call any functions of the CString object once you've called GetBuffer() until you call ReleaseBuffer(). If you're dumb enough to go calling CString functions when you have a pointer to the data, you're too dumb to be using new, since that requires just as much caution.
How exactly should I "have a damn well good idea" of how much data is in a registry key before hand? If my program wrote the data, fine, but if I'm reading reg keys that i didn't write, I have no idea.
String objects are fairly efficient due to reference counting. I can copy them by value or reference and they're roughly the same. Only if I need to modify the string does it matter.
You seem to have these preconcieved notions that all programs should know ahead of time exactly how much memory they need to allocate. That's simply not true of many kinds of apps, especially those that deal with data that were not written by the app. Your argument about know if it's text data or not is irrelevant, since it's quite simple to test the data in the file.
My argument about less code is an argument about readability of the code. The less code you have, the easier it is to read (as long as you're not entering the obfuscated C contest) and understand. It has nothing to do with how much code gets executed.
There is no difference between NUL and NULL in C++. Both are 0. In C, NULL is a (void*)0, while NUL is a literal 0.
As for remembering whether to put a null at the end of the string, there are many C functions which do not put NUL's at the end. strncpy doesn't for instance, and you have to know this to put the null in yourself, while strcpy does. The point is that you *ALWAYS* had best know whether there is a null there or not, or you are incompetant. Even if you don't know, you don't have to guess. Put a null in anyways, whether you need it or not. The documentation is misleading, in that they are saying you don't *HAVE* to put a null in when specifying a length to ReleaseBuffer, not that you aren't supposed to.
And what makes you think that using CString won't inform you if you overrun memory?
|
|
|
|
|
> The GetBuffer() pointer is valid until you call ReleaseBuffer. Period.
> As long as you don't call ReleaseBuffer, the pointer can be stored, copied,
> read from, written to, all without the buffer becoming invalid.
> *JUST LIKE A NEW'D POINTER*
Uh, no... The pointer becomes invalid under certain situations, like reallocation of the internal buffer (assign a much longer string into it), copying another CString into it, etc. (Friendly Tip: test such things before publishing them.) Period.
> If you're dumb enough to go calling CString functions when you have a pointer
> to the data, you're too dumb to be using new, since that requires just as
> much caution.
A pointer allocated via "new" does not become invalid the next time "new" is called. Nor does it become invalid after scope where "new" was called ends (unlike a CString object going out of scope). A pointer obtained via GetBuffer() is a different story, even by your own words. This is exactly the reason why the argument about not using GetBuffer got started. Because the pointer returned by that function requires special handling (of the object).
> so you can't call any functions of the CString object once you've called
> GetBuffer() until you call ReleaseBuffer().
Make up yer mind. Which is it? "until you call ReleaseBuffer()", or "can't call any functions of the CString object"? Talking about not making sense...
>> None of what you claim is any more dangerous than calling
>> new and delete to create dynamic memory.
You (and I both) just mentioned one reason why using GetBuffer() to obtain a pointer is more dangerous than using "new".
> How exactly should I "have a damn well good idea" of how much data is in a
> registry key before hand? If my program wrote the data, fine, but if I'm
> reading reg keys that i didn't write, I have no idea.
If you have no idea, then you also have no idea if the data you are going to be reading is binary or not. Hence, using a CString-based buffer, to hold data that could contain NUL characters is stupid. (And, yes, I do know that you can get both bits of info at runtime.)
> You seem to have these preconcieved notions that all programs should know
> ahead of time exactly how much memory they need to allocate.
No, I have experienced notions that you should know (or at least have an idea about) what you are getting yourself into before starting a project. Serious developers know how important research is (or as our local Guru puts it, "Think first, code later").
(Lots of misreading going on here... Am I not writing clearly enough?)
> String objects are fairly efficient due to reference counting.
> I can copy them by value or reference and they're roughly the same.
VERY roughly... The implementation is not the best that I have seen.
> Your argument about know if it's text data or not is irrelevant, since it's
> quite simple to test the data in the file.
In practice, it is not. How many characters to you test before you decide? The argument was not for a text .vs. binary file, it was for not using a CString-based buffer for data that you know nothing about in the first place.
> My argument about less code is an argument about readability of the code.
So it is not really about "less code", as you said, which was incorrect.
> There is no difference between NUL and NULL in C++. Both are 0.
> In C, NULL is a (void*)0, while NUL is a literal 0
While in C++, yes, NULL is 0. However, NUL can be char-sized, or wchar_t-sized. NULL is (usually) int-sized. A literal "0" is (usually) int-sized. Note the difference? Good. I knew you could.
> As for remembering whether to put a null at the end of the string, there
> are many C functions which do not put NUL's at the end.
Been reading the reference again, eh?
> The point is that you *ALWAYS* had best know whether there is a null there
> or not, or you are incompetant.
Correct. So why bother confusing newer developers by giving them the temptation to NOT manually put one in by using the CString-based buffers?
> And what makes you think that using CString won't inform you if you
> overrun memory?
Mind-reading now? I never said, or thought for that matter, that the debug features of VC would not catch things like that. I said that overruns in local buffers (stack-based) are easier to catch, and typically caught sooner, than heap-allocated ones. Your stack overruns can be found at the close of scope where the buffer was allocated. Heap based ones are usually found at "delete" time for that buffer, or if the heap is trashed badly enough, at the next heap operation.
Also, if you actually overrun the CString buffer, the debug-heap catches it, not CString itself.
BTW: There is such a thing as quitting while you (think you) are ahead...
-=- James.
|
|
|
|
|