i have problem with QStandardItemModel. I want to get values from one model (id, name, parent) and build tree in another model.
First i'm getting all childrens of any parent to QMultiMap<int,QStandardItem*> childrenIndexes:
getChildrens()
{
for(int i = 0 ; i < tableModel->rowCount() ; i++ )
{
QStandardItem* item_ptr = tableModel->item(i,1);
int parent;
if(tableModel->item(i,2)->text() == "null")
{
parent = -1;
}
else
{
parent = tableModel->item(i,2)->text().toInt();
}
childrenIndexes.insert(parent, item_ptr);
}
}
Multimap builds fine, in next step i recursively call building function. Starting from root (Item 1):
void addChildrens(QStandardItem* item)
{
int id = tableModel->item(tableModel->indexFromItem(item).row(),0)->text().toInt();
QString name = tableModel->item(tableModel->indexFromItem(item).row(),1)->text();
qDebug() << "Parsing item: " << name;
int parent;
if(tableModel->item(tableModel->indexFromItem(item).row(),2)->text() == "null")
{
qDebug() << "Got root!";
item = new QStandardItem(name);
treeModel->appendRow(item);
parent = -1;
}
else
{
parent = tableModel->item(tableModel->indexFromItem(item).row(),2)->text().toInt();
}
qDebug("Got %d childrens!",childrenIndexes.values(id).count());
for(int i = 0 ; i < childrenIndexes.values(id).count() ; i++)
{
QStandardItem* newItem = childrenIndexes.values(id).at(i);
qDebug() << newItem->text();
item->appendRow(newItem->clone());
addChildrens(newItem);
}
}
Unfortunately my tree got only childrens of root. Where is problem?
Related
i have been working on a QT application using the QGraphicsPolygonItem. First i created a class called DiagramScene who inherites the QGraphicsScene. First i create the item and put red corners in every point of the Polygon:
item = new DiagramItem(myItemType, myItemMenu);
item->setBrush(myItemColor);
addItem(item);
item->setPen(QPen(myLineColor, 2));
item->setPolygon(mouseEvent->scenePos());
item->setSelected(true);
emit itemInserted(item);
this->putPointsOnItem(item);
The the putPointsOnItem function:
void DiagramScene::putPointsOnItem(DiagramItem *item) {
qDebug() << "putPointsOnItem";
removeControlPoints();
QPolygonF p = item->polygon();
poly_points.clear();
poly_points = p;
qDebug() << p;
for (int i = 0; i < p.size(); i++) {
QPointF point = item->mapToScene(p[i]);
QGraphicsEllipseItem *ellipse = addEllipse(QRectF(point.x() -5, point.y() -5, 8, 8), QPen(Qt::red, 3), QBrush(QColor("red")));
ellipse->setFlag(QGraphicsItem::ItemIsMovable);
ellipse->setZValue(100000000);
corner_points.append(ellipse);
real_corners.append(item);
}
}
Then i check if the corner is selected:
void DiagramScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) {
if (mouseEvent->button() != Qt::LeftButton) {
return;
}
this->finded = false;
for (int i = 0; i < this->corner_points.length(); i++) {
QGraphicsEllipseItem *item = this->corner_points[i];
qDebug() << item;
if (item->contains(mouseEvent->scenePos())) {
item->setSelected(true);
const QList<QGraphicsItem *> items = selectedItems();
if (items.length()>0) {
DiagramItem *startItem = qgraphicsitem_cast<DiagramItem *>(items.first());
startItem->setFlag(QGraphicsItem::ItemIsMovable, false);
selectedItem = startItem;
}
this->selected_corner = item;
this->selected_corner_point = this->poly_points[i];
selected_corner_number = i;
finded = true;
break;
}
}
if (this->finded == true) {
QGraphicsScene::mousePressEvent(mouseEvent);
qDebug() << "POLY POINTS FINDED:";
qDebug() << poly_points;
return;
}
And when the user move the mouse i check the selected corner and put the mouse position into one of the points:
void DiagramScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) {
QGraphicsScene::mouseMoveEvent(mouseEvent);
QString coord = QString("%1, %2").arg(mouseEvent->scenePos().x()).arg(mouseEvent->scenePos().y());
parentMain->setCoordinates(coord);
if ((mouseEvent->buttons() & Qt::LeftButton)) {
const QList<QGraphicsItem *> items = selectedItems();
if (finded == true) {
finded = false;
for (int i = 0; i < corner_points.size(); ++i) {
if (corner_points.at(i) == selected_corner) {
poly_points[selected_corner_number] = mouseEvent->scenePos();
finded = true;
break;
}
}
if (finded) {
qDebug() << poly_points;
selectedItem->setPolygonItem(poly_points);
return;
}
Until that everithing works fine, but when the user move the item, the position dont work as i expected. For now i'm going crazy for many days and need help with this. Thanks a lot!
I think the problem is here:
poly_points[selected_corner_number] = mouseEvent->scenePos();
problem image described
Your comments pointed me in the right direction and I found the solution:
poly_points[selected_corner_number] = selectedItem->mapFromScene(mouseEvent->scenePos());
Thanks a lot!
Trying to create a Hash Table with name as key and it's value as the drink, when printTable() is invoked without adding items (i.e. commenting out the following code snippet) it prints out the added image without any address boundary error :
h.addItem("Paul", "Locha");
h.addItem("Kim", "Iced Mocha");
h.addItem("Emma", "Strawberry Smoothy");
h.addItem("Annie", "Hot Chocolate");
h.addItem("Sarah", "Passion Tea");
h.addItem("Pepper", "Caramel Mocha");
h.addItem("Mike", "Chai Tea");
h.addItem("Steve", "Apple Cider");
h.addItem("Bill", "Root Bear");
h.addItem("Marie", "Skinny Latte");
Image of output with given default values
But when items are added either by parsing csv or directly calling the class member function of addItem(), the program renders an error like so :
➜ Hash Table ./hashTableWithStruct.o
fish: Job 1, './hashTableWithStruct.o' terminated by signal SIGSEGV (Address boundary error)
The erroneous code is herewith :
hashTableWithStruct.cpp
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
class Hash
{
private:
static const int tableSize = 10;
struct item
{
string name;
string drink;
item *next;
};
item *hashTable[tableSize];
public:
Hash()
{
for (int i = 0; i < tableSize; i++)
{
hashTable[i] = new item;
hashTable[i]->name = "empty";
hashTable[i]->drink = "empty";
hashTable[i]->next = NULL;
}
}
int hashFunct(string key)
{
int hashed = 0;
for (int i = 0; key[i] != '\0'; i++)
{
hashed += (int)key[i];
}
return (hashed % tableSize); //returns the BUCKET value
}
void addItem(string name, string drink)
{
int BUCKET = hashFunct(name);
//if the value at BUCKET hasn't been written yet,
//override the default empty ones
if (hashTable[BUCKET]->name == "empty")
{
hashTable[BUCKET]->name = name;
hashTable[BUCKET]->drink = drink;
}
//otherwise, make a linked list starting from BUCKET
else
{
item *ptr = hashTable[BUCKET];
item *n = new item;
n->name = name;
n->drink = drink;
n->next = NULL;
//the linked list might contain many nodes,
//hence travel to last node and reassign the last node to be this new item
while (ptr != NULL)
ptr = ptr->next;
ptr->next = n;
}
return;
}
int numOfItemsInBucket(int BUCKET)
{
int count = 0;
if (hashTable[BUCKET]->name == "empty")
return count;
else
{
count++;
item *ptr = hashTable[BUCKET];
while (ptr->next != NULL)
{
count++;
ptr = ptr->next;
}
}
return count;
}
void printTable()
{
int num; //holds number of elements(items) in each bucket
for (int i = 0; i < tableSize; i++)
{
num = numOfItemsInBucket(i);
cout << "-----------------------------\n"
<< "Table[" << i << "]" << endl
<< hashTable[i]->name << endl
<< hashTable[i]->drink << endl
<< "# of items in bucket " << i << " : " << num << endl;
cout << "-----------------------------\n";
}
}
};
int main(int argc, char const *argv[])
{
Hash h;
/* string filename = "datasetForHashTable.csv";
ifstream myCSV(filename.c_str());
if (!myCSV.is_open())
{
cout<<"Failed to open file"<<endl;
return 0;
}
string name, drink;
while (myCSV.peek()!=EOF)
{
getline(myCSV, name, ',');
getline(myCSV, drink, '\n');
h.addItem(name, drink);
}
myCSV.close(); */
h.addItem("Paul", "Locha");
h.addItem("Kim", "Iced Mocha");
h.addItem("Emma", "Strawberry Smoothy");
h.addItem("Annie", "Hot Chocolate");
h.addItem("Sarah", "Passion Tea");
h.addItem("Pepper", "Caramel Mocha");
h.addItem("Mike", "Chai Tea");
h.addItem("Steve", "Apple Cider");
h.addItem("Bill", "Root Bear");
h.addItem("Marie", "Skinny Latte");
h.printTable();
return 0;
}
Basically, can't understand why the table won't print with name and drinks, since it works just fine when table is printed without it.
Please help, trying to figure this out since 2 days.
After this while loop
while (ptr != NULL)
ptr = ptr->next;
the pointer ptr is equal to nullptr. So the next statement
ptr->next = n;
invokes undefined behavior due to dereferencing a null pointer.
It seems you mean
while (ptr->next != NULL)
ptr = ptr->next;
ptr->next = n;
I try to dynamically create graphs which can have unreachable nodes. These nodes will be converted as new graphs on creation. Then I save all graphs in a map of <string,shared_ptr>.
A MaterialArch is a graph
A MatArchNode is a node
Creation of the main graph :
void Console::newMaterial(std::string name, int size){
if(!isVariable(name)){
if(!inMaterial(name)){
std::shared_ptr<MaterialArch> mat = std::make_shared<MaterialArch>(m_matPop.get());
mat->generate(size);
m_matPop->add(name,mat);
}
}
else{
print("Error : Material name already used");
}
}
The generate function where unreachable nodes are converted to graph :
void MaterialArch::generate(int nbNodes){
std::vector<std::shared_ptr<MatArchNode>> nodeList;
if(m_root == nullptr){
m_root = std::make_shared<MatArchNode>();
m_root->generate();
nodeList.push_back(m_root);
for (int i = 1; i < nbNodes; ++i) {
std::shared_ptr<MatArchNode> nextNode = std::make_shared<MatArchNode>();
nextNode->generate();
nodeList.push_back(nextNode);
}
if(nodeList.size() < 2){
return;
}
for (auto node : nodeList) {
//linking
}
}
std::vector<std::shared_ptr<MatArchNode>> newRoots;
for (auto node : nodeList) {
bool unreachable = true;
if(!node->orpheline(m_root)){
unreachable = false;
}
for (auto root : newRoots) {
if(!node->orpheline(root)){
unreachable = false;
}
}
if(unreachable){
std::cout << "#ORPH" << std::endl;
std::shared_ptr<MaterialArch> orph = std::make_shared<MaterialArch>(m_matPop.get());
orph->setRoot(node);
m_pop->add(m_pop->orphName(),orph);
newRoots.push_back(node);
}
}
}
The function where I put the graph in the map :
void MaterialPop::add(std::string name, std::shared_ptr<MaterialArch> mat){
std::cout << "ADD : "<<name << std::endl;
bool alreadyExist = false;
for (auto var : m_varMaterials) {
if(var.second == mat){
alreadyExist = true;
}
}
if(!alreadyExist){
m_console->addMatName(name);
m_varMaterials.emplace(name,std::move(mat));
m_views.emplace(name, std::make_shared<MaterialArchView>(m_varMaterials.at(name)));
m_visibility.emplace(name,true);
}
}
My problem is as soon as I get out of generate(), every orph shared_ptr is empty. I thought it was because I try to access a deleted object but the main graph is created the same way, in a function, and is not empty out of it.
Thanks in advance for helping
Sorry I'm so bad, my setRoot() looked like :
if(!orpheline(node)){
m_root = node;
}
so the root wasn't set because node was always unreachable
I'm trying to implement AVL Tree in C++, but I'm stuck with the insertion, I have changed some things but nothing seemed to effectively solve the problem. I used Xcode's Address Sanitizer and I'm getting that error after inserting a second element into the tree:
Thread 1: Use of deallocated memory detected.
==3822==ERROR: AddressSanitizer: heap-use-after-free on address.....
This is the implementation of the tree so far:
RoadTree.hpp
#ifndef RoadTree_hpp
#define RoadTree_hpp
#include "Road.hpp"
class RoadTree {
private:
struct TreeNode {
Road *key;
TreeNode *rightChild;
TreeNode *leftChild;
int height;
TreeNode() : key(NULL), rightChild(NULL), leftChild(NULL), height(0) { }
TreeNode(Road *r) : key(r), rightChild(NULL), leftChild(NULL), height(0) { }
};
TreeNode *root;
int numberOfRoads;
int GetHeight(TreeNode *n) const;
void SimpleRightRotation(TreeNode *&n);
void DoubleRightRotation(TreeNode *&n);
void SimpleLeftRotation(TreeNode *&n);
void DoubleLeftRotation(TreeNode *&n);
void Insert(TreeNode *&n, Road *r);
void ClearTree(TreeNode *&n);
void PreOrder(TreeNode *n) const;
public:
RoadTree();
~RoadTree();
void Insert(Road *r);
Road *FindRoad(string destination);
void ListRoads();
void ClearTree();
void PreOrder();
inline int RoadCount() {
return numberOfRoads;
}
};
#endif /* RoadTree_hpp */
RoadTree.cpp
#include "RoadTree.hpp"
RoadTree::RoadTree() : root(NULL), numberOfRoads(0) { }
RoadTree::~RoadTree() {
ClearTree(root);
}
void RoadTree::Insert(Road *r) {
Insert(root, r);
}
int RoadTree::GetHeight(TreeNode *n) const {
if (n == NULL)
return -1;
else
return n->height;
}
void RoadTree::SimpleRightRotation(TreeNode *&n) {
TreeNode *tempNode = n->rightChild;
n->rightChild = tempNode->leftChild;
tempNode->leftChild = n;
n->height = 1 + max(GetHeight(n->leftChild), GetHeight(n->rightChild));
n = tempNode;
tempNode->height = 1 + max(n->height, GetHeight(tempNode->rightChild));
}
void RoadTree::DoubleRightRotation(TreeNode *&n) {
SimpleLeftRotation(n->rightChild);
SimpleRightRotation(n);
}
void RoadTree::SimpleLeftRotation(TreeNode *&n) {
TreeNode *tempNode = n->leftChild;
n->leftChild = tempNode->rightChild;
tempNode->rightChild = n;
n->height = 1 + max(GetHeight(n->leftChild), GetHeight(n->rightChild));
n = tempNode;
tempNode->height = 1 + max(n->height, GetHeight(n->leftChild));
}
void RoadTree::DoubleLeftRotation(TreeNode *&n) {
SimpleRightRotation(n->leftChild);
SimpleLeftRotation(n);
}
void RoadTree::ClearTree(TreeNode *&n) {
if (n != NULL) {
ClearTree(n->rightChild);
ClearTree(n->leftChild);
delete n;
}
n = NULL;
}
void RoadTree::Insert(TreeNode *&n, Road *r) {
if (n == NULL) {
n = new TreeNode(r);
numberOfRoads++;
} else {
if (r->GetDestination() < n->key->GetDestination()) {
Insert(n->leftChild, r);
if ((GetHeight(n->leftChild) - GetHeight(n->rightChild)) == 2) {
if (r->GetDestination() < n->leftChild->key->GetDestination())
SimpleLeftRotation(n);
else
DoubleLeftRotation(n);
}
} else if (r->GetDestination() > n->key->GetDestination()) {
Insert(n->rightChild, r);
if ((GetHeight(n->rightChild) - GetHeight(n->leftChild)) == 2) {
if (r->GetDestination() > n->rightChild->key->GetDestination())
SimpleRightRotation(n);
else
DoubleRightRotation(n);
}
} else if (r->GetDestination() == n->key->GetDestination())
n->key->SetRoad(r->GetDestination(), r->GetCost(), r->GetInfo());
}
n->height = 1 + max(GetHeight(n->leftChild), GetHeight(n->rightChild));
}
Road *RoadTree::FindRoad(string destination) {
TreeNode *n = root;
while (n != NULL) {
string current = n->key->GetDestination();
if (destination < current)
n = n->leftChild;
else if (destination > current)
n = n->rightChild;
else if (destination == current)
return n->key;
}
return NULL;
}
void RoadTree::PreOrder(TreeNode *n) const {
if (n != NULL) {
cout << " " << n->key->GetDestination() << " ";
PreOrder(n->leftChild);
PreOrder(n->rightChild);
}
}
void RoadTree::PreOrder() {
PreOrder(root);
}
void RoadTree::ListRoads() {
}
void RoadTree::ClearTree() {
ClearTree(root);
}
And this is the implementation of Road:
Road.hpp
#ifndef Road_hpp
#define Road_hpp
#include <iostream>
using namespace std;
class Road {
private:
string destination;
int cost;
string info;
public:
Road();
Road(string destination, int cost, string info);
inline string GetDestination() {
return destination;
}
inline int GetCost() {
return cost;
}
inline string GetInfo() {
return info;
}
};
#endif /* Road_hpp */
Road.cpp
#include "Road.hpp"
Road::Road() {
destination = "";
cost = 0;
info = "";
}
Road::Road(string destination, int cost, string info) {
this->destination = destination;
this->cost = cost;
this->info = info;
}
The only way I can insert more than 1 element is leaving the destructor blank, then no error shows, so I don't know what's causing it to fail. The error is showing up at the Insertion method, in the line that compares the elements in order to advance in the tree.
Update: Since this is part of a bigger project, I'm almost 100% sure that the problem isn't from the tree's implementation (I put the tree and Road class in a separate project and everything worked as intended). The full project has a class called Place, it has a name and info, as well as an AVL Tree for each place (where I store the place's roads). Those places are stored in a Hash Table (that I have implemented myself).
This is the implementation of the Place class:
Place.hpp
#ifndef Place_hpp
#define Place_hpp
#include <iostream>
#include "Road.hpp"
#include "RoadTree.hpp"
using namespace std;
class Place {
private:
string name;
string info;
RoadTree adjacentRoads;
public:
Place();
Place(string name, string info);
void InsertRoad(Road *r);
Road *FindRoad(string destination);
void ListRoads();
inline string GetName() {
return name;
}
inline string GetInfo() {
return info;
}
inline void SetPlace(string newName, string newInfo) {
name = newName;
info = newInfo;
}
inline void Write() {
cout << name << endl;
cout << "Info: " << info << endl;
}
};
Place.cpp
#include "Place.hpp"
Place::Place() {
name = "";
info = "";
}
Place::Place(string name, string info) {
this->name = name;
this->info = info;
}
void Place::InsertRoad(Road *r) {
adjacentRoads.Insert(r);
}
Road *Place::FindRoad(string destination) {
return adjacentRoads.FindRoad(destination);
}
void Place::ListRoads() {
adjacentRoads.ListRoads();
}
This is how I get a pointer from the Hash Table (if the full code is needed tell me):
Place *HashTable::Find(string key) {
unsigned long hashedKey = HashFunction(key);
list<Place>::iterator current;
for (current = table[hashedKey].begin(); current != table[hashedKey].end(); current++) {
Place currentPlace = *current;
if (currentPlace.GetName() == key)
return &*current;
}
return NULL;
}
And this is an example of a main that gives me the Thread 1: Use of deallocated memory detected. error
int main(int argc, const char * argv[]) {
//Declare a HashTable to store Places
HashTable map;
//Declare some places
Place p1("Murcia", "10");
Place p2("Lorca", "11");
Place p3("Cartagena", "12");
Place p4("Zaragoza", "13");
Place p5("Madrid", "14");
Place p6("Galicia", "15");
//Insert those places into the HashTable
map.Insert(p1);
map.Insert(p2);
map.Insert(p3);
map.Insert(p4);
map.Insert(p5);
map.Insert(p6);
//Declare some roads
Road *r1 = new Road(p2.GetName(), 20, "asdgasdg");
Road *r2 = new Road(p3.GetName(), 61, "asdgsw2");
//Get a pointer of a place from the HashTable to insert roads in it
Place *p1f = map.Find(p1.GetName());
//Check if it's not null, if it's not then insert the first road,
//get a pointer of it and print the name
if (p1f != NULL) {
p1f->InsertRoad(r1);
Road *r1f = p1f->FindRoad(p2.GetName());
cout << r1f->GetDestination() << endl;
}
//Get pointer of a place again (each time you want to insert a road
//in a place you must get it's pointer from the HashTable
Place *p2f = map.Find(p1.GetName());
//Checks again and insert second road, then throws error after that
if (p2f != NULL) {
p2f->InsertRoad(r2);
Road *r2f = p1f->FindRoad(p3.GetName());
cout << r2f->GetDestination() << endl;
}
return 0;
Update 2: Added HashTable implementation
HashTable.hpp
#ifndef HashTable_hpp
#define HashTable_hpp
#include "Place.hpp"
#include <list>
class HashTable {
private:
list<Place> *table;
int numberOfEntries;
int currentTableSize;
float maxLoadFactor;
unsigned int HashFunction(string key);
bool LoadFactorExceeded();
void ResizeTable();
bool IsPrime(int number);
int NextPrime(int number);
public:
HashTable();
~HashTable();
void Insert(Place p);
Place *Find(string key);
void EmptyTable();
void ListPlaces();
inline int Count() {
return numberOfEntries;
}
};
#endif /* HashTable_hpp */
HashTable.cpp
#include "HashTable.hpp"
#include <algorithm>
const int START_SIZE = 101;
HashTable::HashTable() {
table = new list<Place>[START_SIZE];
numberOfEntries = 0;
maxLoadFactor = 2.0f;
currentTableSize = START_SIZE;
for (int i = 0; i < START_SIZE; i++) {
table[i].clear();
}
}
HashTable::~HashTable() {
delete [] table;
}
unsigned int HashTable::HashFunction(string key) {
unsigned long hashValue = 0;
for (int i = 0; i < key.length(); i++)
hashValue = 47 * hashValue + key[i];
return (hashValue % currentTableSize);
}
bool HashTable::LoadFactorExceeded() {
float currentLoadFactor = numberOfEntries / currentTableSize;
if (currentLoadFactor > maxLoadFactor)
return true;
else
return false;
}
void HashTable::ResizeTable() {
list<Place> *oldTable = table;
int oldTableSize = currentTableSize;
currentTableSize *= 2;
currentTableSize = NextPrime(currentTableSize);
table = new list<Place>[currentTableSize];
for (int i = 0; i < currentTableSize; i++)
table[i].clear();
numberOfEntries = 0;
for (int i = 0; i < oldTableSize; i++) {
list<Place>::iterator current;
for (current = oldTable[i].begin(); current != oldTable[i].end(); current++)
Insert(*current);
}
delete [] oldTable;
}
bool HashTable::IsPrime(int number) {
if (number % 2 == 0 || number % 3 == 0)
return false;
int divisor = 6;
while (divisor * divisor - 2 * divisor + 1 <= number) {
if (number % (divisor - 1) == 0)
return false;
if (number % (divisor + 1) == 0)
return false;
divisor += 6;
}
return true;
}
int HashTable::NextPrime(int number) {
while (!IsPrime(++number)) {}
return number;
}
void HashTable::Insert(Place p) {
unsigned long hashedKey = HashFunction(p.GetName());
list<Place>::iterator current = table[hashedKey].begin();
if (!table[hashedKey].empty()) {
for (current = table[hashedKey].begin(); current != table[hashedKey].end(); current++) {
Place ¤tPlace = *current;
if (currentPlace.GetName() == p.GetName()) {
currentPlace.SetPlace(p.GetName(), p.GetInfo());
break;
} else if (current == --table[hashedKey].end()) {
table[hashedKey].push_back(p);
numberOfEntries++;
}
}
} else {
table[hashedKey].push_back(p);
numberOfEntries++;
}
if (LoadFactorExceeded())
ResizeTable();
}
Place *HashTable::Find(string key) {
unsigned long hashedKey = HashFunction(key);
list<Place>::iterator current;
for (current = table[hashedKey].begin(); current != table[hashedKey].end(); current++) {
Place currentPlace = *current;
if (currentPlace.GetName() == key)
return &*current;
}
return NULL;
}
void HashTable::EmptyTable() {
for (int i = 0; i < currentTableSize; i++) {
table[i].clear();
}
table = new list<Place>[START_SIZE];
numberOfEntries = 0;
currentTableSize = START_SIZE;
}
void HashTable::ListPlaces() {
list<string> places;
for (int i = 0; i < currentTableSize; i++) {
list<Place>::iterator current;
for (current = table[i].begin(); current != table[i].end(); current++)
places.push_back(current->GetName());
}
places.sort();
for (list<string>::iterator current = places.begin(); current != places.end(); current++)
cout << *current << endl;
cout << "Total: " << numberOfEntries << " lugares" << endl;
}
What could be causing the problem?
I'm not sure if this is it, but I noticed something: it looks like a linked list, and your recursive ClearTree function will attempt to free items repeatedly:
void RoadTree::ClearTree(TreeNode *&n) {
if (n != NULL) {
ClearTree(n->rightChild);
ClearTree(n->leftChild);
delete n;
}
n = NULL;
}
Assuming there are 2 elements in the list, and we call it with the first element:
ClearTree( firstElement );
It will then first
ClearTree(n->rightChild); // 2nd element
which in turn will first call
ClearTree(n->rightChild); // non-existing 3rd element: NOP
and proceed with
ClearTree(n->leftChild); // first element again
Maybe if you didn't get the error, this would recurse until you get a stack overflow?
You could simply remove the call to ClearTree(n->leftChild) to fix it; the function will recurse across the rightChild until it reaches the end, then delete the nodes from last to first when it backtracks.
Perhaps it's better to just iterate over the list: (untested, hope this works)
TreeNode * cur = n;
while ( cur != NULL )
TreeNode * next = n->rightChild;
delete cur;
cur = next;
}
n = NULL;
UPDATE
I've found the problem. Here's my debug output:
> g++ -O0 -g *cpp && gdb ./a.out
(gdb) r
Starting program: /home/kenney/roadtree/a.out
= INITIALIZING PLACES =
--> RoadTree[0x7fffffffe1a0] CONSTRUCTOR root: 0
--> RoadTree[0x7fffffffe1c0] CONSTRUCTOR root: 0
--> RoadTree[0x7fffffffe1e0] CONSTRUCTOR root: 0
--> RoadTree[0x7fffffffe200] CONSTRUCTOR root: 0
--> RoadTree[0x7fffffffe220] CONSTRUCTOR root: 0
--> RoadTree[0x7fffffffe240] CONSTRUCTOR root: 0
= INSERTING PLACES =
<-- RoadTree[0x7fffffffe340] DESTRUCTOR! root: 0
<-- RoadTree[0x7fffffffe360] DESTRUCTOR! root: 0
<-- RoadTree[0x7fffffffe380] DESTRUCTOR! root: 0
<-- RoadTree[0x7fffffffe3a0] DESTRUCTOR! root: 0
<-- RoadTree[0x7fffffffe3c0] DESTRUCTOR! root: 0
<-- RoadTree[0x7fffffffe3e0] DESTRUCTOR! root: 0
= CREATING ROADS =
These are the p1..p6 and the map.Insert(p1..p6). There's already a hint that something is wrong. Next this code is run:
cout << "= p1 =\n";
Place *p1f = map.Find(p1.GetName());
cout << "found " << p1f << " for " << p1.GetName() << "\n";
Producing this debug output:
= p1 =
<-- RoadTree[0x7fffffffe110] DESTRUCTOR! root: 0
found 0x6098f0 for Murcia
Then,
if (p1f != NULL) {
p1f->InsertRoad(r1);
Road *r1f = p1f->FindRoad(p2.GetName());
cout << r1f->GetDestination() << endl;
}
outputting this debug from RoadTree::Insert, indicating that the first if statement's 'then' is executed, assigning a new TreeNode to n:
n null, allocating.
--> TreeNode[0x609ad0] CONSTRUCTOR
allocated TreeNode 0x609ad0 key: 0x609a60 dest: Lorca
Lorca
So far so good, now the same again for p2. First the output of map.Find:
= p2 =
FINDING Murcia
<-- RoadTree[0x7fffffffe110] DESTRUCTOR! root: 0x609ad0
!!! RoadTree::ClearTree:: delete 0x609a60
<-- TreeNode[0x609ad0] DESTRUCTOR
found 0x6098f0 for Murcia
Next we continue to p2f->InsertRoad(r2); which is basically Place.adjacentroads.Insert aka RoadTree.insert:
n not null: 0x609ad0 key: 0x609af0
Note the address of n: this is the deleted TreeNode.
Here, the 'else' of the 'if' in RoadTree::Insert is taken since n != NULL:
if (r->GetDestination() < n->key->GetDestination()) {
is executed, causing:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7b9126b in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
(gdb) bt
#0 0x00007ffff7b9126b in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1 0x00000000004046b3 in Road::GetDestination (this=0x609af0) at Road.hpp:20
#2 0x0000000000405121 in RoadTree::Insert (this=0x609900, n=#0x609900: 0x609ad0, r=0x609ab0) at RoadTree.cpp:75
#3 0x0000000000404c0d in RoadTree::Insert (this=0x609900, r=0x609ab0) at RoadTree.cpp:15
#4 0x0000000000404845 in Place::InsertRoad (this=0x6098f0, r=0x609ab0) at Place.cpp:14
#5 0x000000000040401d in main (argc=1, argv=0x7fffffffe5f8) at main.cpp:63
(gdb)
The fault is apparent in the n->key->GetDestination() which attempts to return a copy of a string that is already deleted, causing a segfault because some pointers are already overwritten.
The problem is in HashTable::Find, which does this:
Place currentPlace = *current;
if (currentPlace.GetName() == key)
return &*current;
which constructs a Place copy on the stack that gets destroyed when the method returns. The private fields of Place also get destroyed, including the string name, which was attempted to be returned by Road::GetDestination().
Replacing it with this with this solves it:
if (current->GetName() == key)
return &*current;
I'm not sure this is the only fix needed, but it's a step.
I am developing a Qt application using QTreeView and QFileSystemModel.
I am able to get the parent's child till one level but I am not able to get the parent's child's child.
For eg:
C is child of B,
B is child of A
I am able to get B as A's child but I also want C as A's Child.
I want like this C->B->A.
Can someone give some input regarding this and help me out.
Thanks in advance.
//QItemSelectionModel *sel = ui->dir_tree->selectionModel();
QStringList strings = extractStringsFromModel(ui->dir_tree->model(), ui->dir_tree->rootIndex());
QFileSystemModel* model = (QFileSystemModel*)ui->dir_tree->model();
QModelIndexList indexlist = ui->dir_tree->selectionModel()->selectedIndexes();
QVariant data;
//QList<QModelIndex> modelindex(indexlist);
int row = -1;
for(int i=0; i<indexlist.size();i=i+4)
{
QModelIndex mi=indexlist.at(i);
info1 = model->fileInfo(mi);
QString childstr = info1.filePath();
QString childname = info1.fileName();
QModelIndex mi2= indexlist.at(i).parent();
info = model->fileInfo(mi2);
QString parentstr = info.filePath();
QString parentname = info.fileName();
QStringList childlist;
for(int j=0;j<model->rowCount(indexlist.at(i));j++)
{
QModelIndex mi3 = indexlist.at(i).child(j, 0);
info2 = model->fileInfo(mi3);
QString childrenstr = info2.filePath();
childlist << childrenstr;
qDebug()<<"parents' children"<<childrenstr<<j;
}
}
I like to use recursion for this kind of thing:
void MyTreeView::GetAllChildren(QModelIndex &index, QModelIndexList &indicies)
{
indicies.push_back(index);
for (int i = 0; i != model()->rowCount(index); ++i)
GetAllChildren(index.child(i,0), indicies);
}
Usage (from somewhere inside the tree view):
QModelIndexList list;
GetAllChildren(model()->index(0,0), list);
Getting all children breadth-first:
QModelIndexList children;
// Get top-level first.
for ( int i = 0; i < model->rowCount(); ++i ) {
children << model->index( i, 0 ); // Use whatever column you are interested in.
}
// Now descend through the generations.
for ( int i = 0; i < children.size(); ++i ) {
for ( int j = 0; j < model->rowCount( children[i] ); ++j ) {
children << children[i].child( j, 0 );
}
}
Getting all parents from a child:
QModelIndexList parents;
parents << child.parent();
while ( parents.last().isValid() ) {
parents << parents.last().parent();
}
Please note, I haven't tried these samples!
//Delete
QList<QTreeWidgetItem *> selected = ui->twg->selectedItems();
QTreeWidgetItem *item = selected.first();
QTreeWidgetItem *parent = item->parent();
if(parent) {
int index = parent->indexOfChild(item);
delete parent->takeChild(index);
}
//Add
QList<QTreeWidgetItem *> selected = ui->twg->selectedItems();
QTreeWidgetItem *item = selected.first();
QTreeWidgetItem *parent = item->parent();
if(parent) {
QTreeWidgetItem *tmp = new QTreeWidgetItem(parent);
tmp->setText(0, "Dude");
parent->addChild(tmp);
}