QList, appending object, loosing static members - c++

I'm using building a QList in my object:
QList<clsXMLnode*> mlstChildren;
In my method to append a child node:
void clsXMLnode::appendChild(clsXMLnode* pobjChild) {
assert(pobjChild != NULL);
mlstChildren.append(pobjChild);
// ...
When I use the debugger to single step I can see that pobjChild has all the static data that it should have associated with it, however the node that is appended to 'mlstChildren' has none of the static members. Using the debugger I can see the 'pobjChild' is still correct and 'mlstChildren' whilst it has the same pointer address for the child node, the contents of it do not match the contents of 'pobjChild', why?
Edit:
It seems to be a bug in the debugger, I modified my appendChild method as follows:
void clsXMLnode::appendChild(clsXMLnode* pobjChild) {
assert(pobjChild != NULL);
int intNewIdx = mlstChildren.length();
mlstChildren.append(pobjChild);
clsXMLnode* pobjCheck = mlstChildren.at(intNewIdx);
// ...
I can see in the debugger that the contents of pobjCheck matches the contents of pobjChild exactly and all static members are intact, but if I expand mlstChildren in the debugger, whilst the class address matches pobjChild, the contents of the static data does not.

This isn't really an answer, however I think I've proven that it is one of several ongoing bugs in the Qt Debugger, which I have reported to the Qt developers forum:
https://forum.qt.io/topic/82279/debugger-and-static-data

Related

add a QListWidgetItem to a QListWidget using a std::shared_ptr to fix fortify issue

Fortify doesn't like QListWidget::addItem(new QListWidgetItem) and reports a false memory leak, even though QT manages the memory properly.
I'm trying to figure out a work-around.
I was told to use a std::shared_ptr, but I haven't figured out the syntax yet.
Here's what I've got so far, but it reports an error about the type.
These 2 lines of code are all I need to fix, there is no further context. Just looking for the syntax for a shared pointer to QListWidgetItem, adding the item to the list widget with addItem().
Any syntax that works is fine. MUST create a QListWidgetItem and THEN add it. Cannot use additem("string") syntax.
In a header file, declare member variable item:
...
class Class1{
...
std::shared_ptr<QListWidgetItem> item;
...
};
In a source file:
...
Class1::ClassFunction1()
{
std::make_shared<QListWidgetItem> item("AStringToAdd");
ui->qlw->addItem(item);
}
As per my comment you might be able to utilize std::unique_ptr to silence fortify...
Class1::ClassFunction1 ()
{
auto item = std::make_unique<QListWidgetItem>("AStringToAdd");
/*
* Use std::unique_ptr::release() to transfer ownership of the
* QListWidgetItem to the QListWidget.
*/
ui->qlw->addItem(item.release());
}
The solution provided in the answer by #hyde is certainly the more robust. Having said that the original post is essentially seeking ways of trying to fix a problem with the fortify tool. So the real solution is "fix the tool" or find other, better analysis tools.
This might do the trick, based on code you show in your question:
class Class1{
...
std::unique_ptr<QListWidgetItem> item; // no need to use shared ptr
std::unique_ptr<...whatever you need here...> ui; // change ui to unique_ptr and put it after the item!
// remember to change construction of `ui` accordingly, and remove deleting it in destructor
...
};
Class1::ClassFunction1()
{
// reset member variable, don't create a new local variable
item.reset(new QListWidgetItem>("AStringToAdd"));
ui->qlw->addItem(item.get()); // pass naked pointer
}
That way, item will go out of scope before ui, and will be deleted by the unique_ptr. When the item is deleted, it will notify the view, and view will remove the item.
If you do it the other way around, view will delete the item, but it has no way to notify the unique_ptr. Therefore unique_ptr will delete it again, resulting in Undefined Behavior, with luck just a crash.

QGraphicsItem is not visible after adding to scene

I'm working on a diagram visualisation tool and I ran into an issue where my QGraphicsScene does not display a shared_ptr<DiagramItem> when a raw pointer obtained via .get() is passed to scene->addItem().
Subsequent check via scene->items() shows that my DiagramItem is not a part of the scene. My guess is that it got freed as the refcounter on the shared_ptr will be zero after leaving the scope of the testing function...
But that was the testing case. In my actual code I'm using a shared_ptr that I got from elsewhere and is definitely present in memory with a non-zero refcounter. I get the raw pointer of that and pass it to scene->addItem(). It is also not displayed, but this time it is present in scene->items(). So why is it not being drawn?
If I switch from using shared_ptr<DiagramItem> to DiagramItem* then the issue disappears and everything is displayed properly. But due to limitations from the rest of the project, I cannot easily abandon smart pointers here, nor do I want to.
Did I run into some kind of memory limitation or am I doing something wrong?
I already tried calling show() and update() on the item and increasing the scene size in case the item doesn't fit (it does). I also tried breakpointing the paint() method, but that one doesn't get called at all.
I found a possibly related question here where similar behaviour occurs due to the object going out of scope and being deallocated, but that doesn't seem to be the case with my actual DiagramItem.
class DiagramItem : public QGraphicsItem
{
...
}
//Create scene
auto scene = new QGraphicsScene(nullptr);
//Item is created OR obtained from elsewhere
auto item1 = std::make_shared<DiagramItem>(nullptr, QString("aaa"), true);
auto item2 = GetDiagramItem(...);
//Raw pointers get passed to addItem
scene->addItem(item1.get());
scene->addItem(item2.get());
//Item1 is not present at all (directly created DiagramItem)
//Item2 is present but invisible (DiagramItem passed from elsewhere)
//myItem gets Item2
auto myItem = scene->items()[0];
...

Application(mfc) failing in Release build due to compiler optimization but working fine in debug build

I am facing issue with Release build. Application works fine in Debug build but in release build a pointer initialized to hold object of another class is getting different address allocation and thus causing corruption to its values.
My main application class is K32App
code in K32App.h file
CSheetPrintManager* m_pSheetPrintManager;
CSheetPrintManager* GetSheetPrintManager() { return m_pSheetPrintManager; }
In file K32App.cpp
K32App::K32App()
{
m_pSheetPrintManager= NULL;
}
BOOL K32App::InitInstance()
{
if(!m_pSheetPrintManager)
m_pSheetPrintManager= new CSheetPrintManager();
}
K32App::~K32App()
{
if(m_pSheetPrintManager)
delete(m_pSheetPrintManager)
}
In my file CSheetPrintManager.cpp
void CSheetPrintManager::CSheetPrintManager()
{
//Initialized all member variables to default values.
Init();
}
void CSheetPrintManager::Init()
{
m_nSheetType = SheetIllegalNone; //long
m_sBankEntry.Empty(); //CString
m_bHistorical = FALSE; //BOOL
m_bDebitDetailsSet = FALSE; //BOOL
m_mapRequested.RemoveAll(); // Type CMap<long,long,CString,CString&>
}
During application startup, when it reaches
if(!m_pSheetPrintManager)
CSheetPrintManager= new CSheetPrintManager();
and tries to create object of m_pSheetPrintManager, 'this' pointer inside CSheetPrintManager.cpp shows valid address (0x03768ce0) at breakpoint just at curly brace {, once I step further into CSheetPrintManager.Init(), 'this' gets different location and starts point to another address(0x0000000) and then further moving it starts pointing another location(0x03786ce0) and then on reaching m_mapRequested.RemoveAll();
'this' is pointing some other location.
returning back to main app file C32App.cpp , I get following for 'm_pSheetPrintManager' CXX0030 Error 'expression cannot be evaluated" in Auto window.
and appplication continues to run. See what get when hover mouse of m_pSheetPrintManager (can't post image because need 10 reputations for it :) so linking it)
studio Auto window screenshot
In debug mode, I get m_pSheetPrintManager pointing to same location during all application processing and members always remain properly initialized.
But in Release mode, m_pSheetPrintManager continues to point (address value shown in Auto window) different location. and all member variables of class CSheetPrintManager showing different garbage(Uninitialized) values with each line of processing inside CSheetPrintManager Class.
If I disable C++ compiler optimization in Release-Mode then it works fine without any issue.
Any help/guidance/suggestion is most appreciated.
Thanks in advance.
PS: This is my first question here so please excuse in case missing something to point or express properly.
You need to provide more info: Is CSheetPrintManager capsuled in a dll? How does the declaration look? This way I only can play guessing games... :-/
Consider to derive from CObject and use DECLARE DYNCREATE and IMPLEMENT_DYNCREATE for your CSheetPrintManagerclass. You can then VERIFY()in your Release version if it's a valid object using CObject::IsKindOf().
Try #pragma pack() to define how padding is done in your class, especially if you optimized for size in the Release version and having mixed-up Debug and Release dlls.

Events wxWidgets

I'd like to understand how to do a specific task. I was trying to set up event tables in wxWidgets and ran into an issue with their behaviour.
I set up some code in one class:
void TopRightPanel::OnSelChanged(wxTreeEvent& event)
{
wxTreeItemId item = event.GetItem();
TreeItemData* data = (TreeItemData *) GetItemData(item);
if(data != NULL)
{
particleSystemManager->SetSelectedParticleSystem(data->particleSystem);
}
}
This works fine and has the right values as expected. My problem with this though is that it's self contained and I want the class above it in the hierarchy to read the treeCtrl's action and make changes to all aspects of the U.I. So I tried this:
void Window::OnSelChanged(wxTreeEvent& event)
{
wxTreeItemId item = event.GetItem();
TreeItemData* data = (TreeItemData *) topRightPanel->GetItemData(item);//item.m_pItem.//m_MyTreeCtrl->GetItemData(itemId);*/
if(data != NULL)
{
particleSystemManager.SetSelectedParticleSystem(data->particleSystem);
}
}
Now I get an unhandled exception when topRightPanel->GetItemData(data) is called. The topRightPanel it uses doesn't seem to be updated and seems to be pointing to data before it's enstantuated in the class' constructor. Is there anyway I can get round this?
Edit:
I declare the event table like so:
#if USE_GENERIC_TREECTRL
BEGIN_EVENT_TABLE(TopRightPanel, wxGenericTreeCtrl)
#else
BEGIN_EVENT_TABLE(TopRightPanel, wxTreeCtrl)
#endif
EVT_TREE_SEL_CHANGED(TopRightPanel_Ctrl, Window::OnSelChanged)
END_EVENT_TABLE()
and I then declare the table in the header using DECLARE_EVENT_TABLE.
You must use the same class name in the event table macros that you used in BEGIN_EVENT_TABLE. IOW, your handler must be defined in Window event table and not in TopRightPanel event table. As tree events are wxCommandEvents, they are propagated upwards to the parent so if Window contains the tree control, this will work. Otherwise, e.g. if they are siblings, you would have to use Connect() as indicated in another answer.
(Re)reading the event handling overview would be highly recommended.
You don't show how do you connect this event handler but the problem is almost surely there and not in the code you show. If you're using Connect(), make sure that you pass the pointer to Window object as its last argument, otherwise you end up calling a method of Window class on TopRightPanel object with the unsurprisingly catastrophic consequences.
If you're sure that you do call the method on the right object, then the only other explanation I see is that you don't initialize topRightPanel before the first event of this type is generated. If this is the case, the simplest solution is to initialize the pointer to NULL and set it correctly at the end of the initialization code. And, of course, check for the pointer being non-NULL in the event handler.

How do I append elements with duplicate names using MSXML & C++?

I am write some code to update a XML DOM using MSXML4 & C++. I need a method that appends a child element to a parent element. The code I have written below works until the title of the child matches the title of another child under the parent. I cannot change the title of the children so I need to find a way to append them to the parent.
Can anyone provide some guidance?
// this call creates '<parent><child/></parent>'
AppendChild("/root/parent", "child");
// this call attempts to create '<parent><child/><child/></parent>' but the DOM remains unchanged ('<parent><child/></parent>')
AppendChild("/root/parent", "child");
void AppendChild(const std::string kPathOfParent, const std::string kNameOfChild)
{
MSXML2::IXMLDOMNodePtr pElement = m_pXmlDoc->createNode(NODE_ELEMENT, kNameOfChild.c_str(), m_xmlns.c_str());
MSXML2::IXMLDOMNodePtr pParent = m_pXmlDoc->selectSingleNode(kPathOfParent.c_str());
MSXML2::IXMLDOMNodePtr pNewChild = pParent->appendChild(pElement);
}
I am not sure exactly what the problem was, but somewhere my binaries were out of step. I rebuilt the entire project via 'Clean Solution' instead of just the 'Build Solution' option. Now both children are created using the code above. It is not clear to me why I was able to step in to the code via the debugger, but the second child was never created until I cleaned the solution.
Jeff & Remy, thank-you for your comments.