-
December 7th, 2011, 11:52 AM
#1
MFC ListBox problem
I am trying to create my own listbox class but failed. Here is the source code:
// MyListBox.h
Code:
class CMyListBox : public CListBox
{
DECLARE_DYNAMIC(CMyListBox)
public:
CMyListBox(void);
virtual ~CMyListBox(void);
int AddDetailedString(const LPCTSTR lpszItem, const CString csDetail);
...
private:
CObArray m_coDetails;
};
// MyListBox.cpp
Code:
IMPLEMENT_DYNAMIC(CMyListBox, CDialog)
CMyListBox::CMyListBox(void) {}
CMyListBox::~CMyListBox(void) {}
int CMyListBox::AddDetailedString(const LPCTSTR lpszItem, const CString csDetail)
{
LPCTSTR lpszDetail = csDetail;
m_coDetails.Add((CObject*)lpszDetail); // this line always crash
return CListBox::AddString(lpszItem);
}
I have no idea why if I delcared a private array (or vector) variable and then push the elements to it. It always crash! If I use CObArray, I got "privileged instruction" promopt and debugger run at "AfxAssertValidObject". If I use std::vector, I got "Access Violation" and debugger run at "CheckBytes".
Please could anyone give me some suggestion to solve this problem?
Many thanks!
Last edited by chesschi; December 7th, 2011 at 12:22 PM.
-
December 7th, 2011, 12:08 PM
#2
Re: MFC ListBox problem
This is a guess, since I am not familiar with CObarray, but ...
Code:
LPCTSTR lpszDetail = csDetail;
m_coDetails.Add((CObject*)lpszDetail); // this line always crash
I am not sure that forcing a non-CObject pointer to a CObject pointer is valid.
Also, there could be scoping problems.
Why not make m_coDetails a CStringArray (or equivalent) ?
-
December 7th, 2011, 12:10 PM
#3
Re: MFC ListBox problem
Basically any container like vector or CStringArray will crash
-
December 7th, 2011, 12:21 PM
#4
Re: MFC ListBox problem
Originally Posted by chesschi
Basically any container like vector or CStringArray will crash
To start with, you are trying to store a variable from the function stack in a list. So, as long as the list that you are using doesn't make a copy of the object, storing it is useless. After the function ends, the stored object in the list will be destroyed. Also, if you run your program in the debugger, the debugger wil stop at the point of the crash and you can see why it crashes.
-
December 7th, 2011, 12:36 PM
#5
Re: MFC ListBox problem
Is it crashing or tripping an ASSERT?
CString is not derived from CObject.
A CStringArray will work, or why not just use the CListBox SetItemData() or SetItemDataPtr() functions?
Last edited by GCDEF; December 7th, 2011 at 12:39 PM.
-
December 7th, 2011, 01:11 PM
#6
Re: MFC ListBox problem
Originally Posted by chesschi
I have no idea why if I delcared a private array (or vector) variable and then push the elements to it. It always crash!
That is exactly the reason why it crashes -- it is "private" or local to the function. When that function returns, that local variable no longer exists.
I'll add to what Skizmo stated:
1) You are storing a pointer in the CObArray. OK, a CObArray can contain pointers, so it looks like it works.
2) Now, that pointer you're storing points to the internal CString you passed in (actually the buffer of characters). So you have a pointer to the CString buffer being placed in the CObArray.
3) That CString is a parameter that was passed by value. Passing by value means that the CString parameter is temporary. When that function exits, that CString is gone down the drain and no longer exists.
Now, do you see why it crashes? That pointer doesn't point to anything valid when that function exits. The CString that was passed in has disappeared into thin air when that function returns. The data that is in the CString no longer is valid. So your container now has a bad pointer within it.
If I use CObArray, I got "privileged instruction" promopt and debugger run at "AfxAssertValidObject". If I use std::vector, I got "Access Violation" and debugger run at "CheckBytes".
All explained above.
Please could anyone give me some suggestion to solve this problem?
My suggestion is to study up on scope, object lifetimes, etc. The issue has nothing to do with CObArray or vector, and has everything to do with not understanding fully how C++ works with respect to functions, variables, and scope. Unless you know these topics, you'll make this same mistake again, and the bad part is that you may not know you've made this mistake until your program is running on someone else's machine and crashes at random times.
Bottom line is that if you're going to store pointers to things in containers such as CObArray or vector, that thing you're pointing to has to be still "alive" when you access it later on.
Regards,
Paul McKenzie
Last edited by Paul McKenzie; December 7th, 2011 at 01:15 PM.
-
December 7th, 2011, 01:19 PM
#7
Re: MFC ListBox problem
I don't think that's the problem Paul. The pointer is still in scope at the time he adds. I'm pretty sure he's casting an CString to a CObject and getting an ASSERT or maybe a crash because he's casting a CString to something it's not.
Regardless, I think it's probably moot as the List Box already has the ability to store pointers built in.
Also, to the OP, are you considering the sort order of your list box?
Last edited by GCDEF; December 7th, 2011 at 01:23 PM.
-
December 7th, 2011, 01:53 PM
#8
Re: MFC ListBox problem
Originally Posted by GCDEF
I don't think that's the problem Paul. The pointer is still in scope at the time he adds. I'm pretty sure he's casting an CString to a CObject and getting an ASSERT or maybe a crash because he's casting a CString to something it's not.
OK. I was looking at the issue differently -- after that function exits. If the OP attempts to do anything with the CObArray, even if that line didn't crash right away, the program is still accessing an invalid pointer.
So there are two problems, the immediate one, and one that would have occurred later on if the first one didn't trip the ASSERT().
Regards,
Paul McKenzie
-
December 7th, 2011, 02:02 PM
#9
Re: MFC ListBox problem
Originally Posted by Paul McKenzie
OK. I was looking at the issue differently -- after that function exits. If the OP attempts to do anything with the CObArray, even if that line didn't crash right away, the program is still accessing an invalid pointer.
So there are two problems, the immediate one, and one that would have occurred later on if the first one didn't trip the ASSERT().
Regards,
Paul McKenzie
Yeah, your point is still valid and still waiting for him. A CStringArray will make both problems go away, assuming he really needs one.
-
December 8th, 2011, 05:00 AM
#10
Re: MFC ListBox problem
Originally Posted by Paul McKenzie
That is exactly the reason why it crashes -- it is "private" or local to the function. When that function returns, that local variable no longer exists.
Thanks Paul. You are right. Actually I am implementing my own tab control and use a CObArray container to store any listbox, button, edit box, etc...
And I use tabCtrl.GetDlgItem(IDC_LISTBOX_XXX) to get my own list box control (not via COBArray). Although the debugger shows an assertion at the point I am stepping through at this line
Code:
m_coDetails.Add((CObject*)lpszDetail);
and before the line
Code:
return CListBox::AddString(lpszItem);
.
I believe it could be the problem that the MS Visual Studio compiler is unable to catch that. It is because, as you mentioned, if I use any private member (e.g. CString, CStringArray, vector, etc...) it will also get the assertion.
Cheers~~!
-
December 8th, 2011, 06:33 AM
#11
Re: MFC ListBox problem
Always store in a CObArray pointers to CObject-derived objects.
Not LPCTSTR, not CString, not CStringArray...
If you want any type of pointers, use CPtrArray.
-
December 8th, 2011, 06:50 AM
#12
Re: MFC ListBox problem
Originally Posted by chesschi
Thanks Paul. You are right. Actually I am implementing my own tab control and use a CObArray container to store any listbox, button, edit box, etc...
And I use tabCtrl.GetDlgItem(IDC_LISTBOX_XXX) to get my own list box control (not via COBArray). Although the debugger shows an assertion at the point I am stepping through at this line
Code:
m_coDetails.Add((CObject*)lpszDetail);
and before the line
Code:
return CListBox::AddString(lpszItem);
.
I believe it could be the problem that the MS Visual Studio compiler is unable to catch that. It is because, as you mentioned, if I use any private member (e.g. CString, CStringArray, vector, etc...) it will also get the assertion.
Cheers~~!
As I've been telling you, the ASSERT is likely because CString is not derived from CObject*.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|