I have a problem when I try to run this code
void MyClass::setUp(){
list->clear();
Iterator i = ctr.getAll().iterator();
while (i.valid()) {
list->addItem(QString::fromStdString(i.elem().getNr()));
i.next();
}
}
When I exit the function an error occurs:
Debug Assertion Failed!
File:C:\Program Files \Microsoft Visual Studio 14.0\ VC\ include\
xmemory0 line:106
Expression: "(_Ptr_user&(_BIG_ALLOCATION_ALIGNMENT -1))==0 " &&0
I am trying to iterate through a custom list
The Iterator class is this:
void Iterator::first(){
while (pos < ht.nrElem && ht.list[pos] == nullptr)
pos++;
if (pos < ht.nrElem)
current = ht.list[pos];
}
Iterator::Iterator(const HashTable & ht): ht { ht }{
pos = 0;
first(); // current will refer the first element of the list
}
void Iterator::next(){
current = current->getNext();
if (current == nullptr) {
pos++;
first();
}
}
bool Iterator::valid(){
return (pos < ht.nrElem) && (current != nullptr);
}
Car& Iterator::elem() const{
return current->getCar();
}
For one thing, Iterator::first and thus the constructor do not neccessarily initialize current. Second, in Iterator::Iterator(const HashTable & ht): ht { ht } does it mean that Iterator has a member ht , and the parameter is also called ht? It is a bad practice. Never call parameters of member functions the same name as class fields.
Related
I am trying to write a BST which performs common operations, Insertion, Deletion, Search, and traversals.
The problem I have found is that the created tree works perfectly when it is assigned to use non-primitive data types, For exmple: user defined struct, classes and C++ stl classes (as std::string)
But when I use int, double_t, int64_t and so, it throws an exception.
~BinaryNode()
{
if (left_ != NULL)
Deleting(left_);
if (right_ != NULL)
Deleting(right_);
//The exception occurs here when the primitive data type
//is attempted to be deallocated
}
//Using preorder to delete this tree recursively
void Deleting(BinaryNode<T> *node)
{
if (node == NULL) return;
if (node->left_ != NULL)
delete node->left_;
if (node->right_ != NULL)
delete node->right_;
node->left_ = node->right_ = NULL;
delete node;
}
I had made many tests, checking the integrity between nodes and that's not the problem. Because, As I said, the problem is when the destructor reaches its end.
When I used the debugger I saw that a std::string calls its destructor and is correctly deallocated. But with primitive types it throws an exception of type:
Exception has occurred.
Trace/breakpoint trap
Thanks Beforehand.
Edit:
I am testing it as:
int main()
{
BinarySearchTree<uint64_t> bst(
[](const uint64_t &t1, const uint64_t &t2) -> int8_t {
if (t1 == t2) return 0;
if (t1 > t2) return 1;
else return -1;
});
//performance slow down because there are (20000^2)/2 operations
//to do. This is not a Self Balanced tree, so it is expected
//it ends having worst performance than a singly linked list
for (size_t i = 0; i <= 200; i++)
// i <= 20000 causes error
// i <= 200 or i <= 2000 works perfect
{
bst.Insert(i);
std::cout << "i:" << i << std::endl;
}
std::cout << bst.Size() << std::endl;
bst.Clear();//this generates the error. [When i <= 20000]
}
Definition of Insert
virtual bool Insert(const T &t)
{
if (this->root_ == NULL)
{
this->root_ = new BinaryNode<T>(t);
return true;
}
return Insert(t, this->root_);
}
virtual bool Insert(const T& t, BinaryNode<T> *node)
{
if (this->comparing_(t, node->t_) > 0)
if (node->left_ == NULL)
{
node->left_ = new BinaryNode<T>(t);
this->size_++;
}
else Insert(t, node->left_);
else if (this->comparing_(t, node->t_) < 0)
if (node->right_ == NULL)
{
node->right_ = new BinaryNode<T>(t);
this->size_++;
}
else Insert(t, node->right_);
else return false; //if there is such element
return true; //if it was successfully inserted
}
This is the definition of Clear
virtual void Clear()
{
delete root_;
root_ = NULL;
}
Note: comparing_ is a lambda.
I think that this is a recursion error.
I found that the error was produced due to a stack overflow error. Why? Because the stack of calls was adding as many calls as nodes were at an unbalanced side of the tree.
Due the nature of an unbalanced binary search tree this happens, there is a limit for recursion. I tried adding 20.000 and 200.000 elements into a AVLTree and it worked fine due the self balancing procedure, because it ensures the tree to have a height O(ln(n))
As I can't see the node class so according to my understanding:
The data types like int can't be assigned NULL.
Creating a template class to insert data recursively in BTree. The code gives segmentation error, I have included the getter and setter functions in header file, not sure where it is going wrong, please help to suggest, if I remove the check on Node->right==NULL, then the code works fine, but in that case I am unable to add recursion.
template <class S>
class STree
{
public:
// Constructors
STree()
{root = NULL; size=0;}
STree(S part)
{root = new BTNode<S>(part); size=0;}
// Destructor
~STree(){};
void insert(S part)
{
if (root == NULL)
{
root = new BTNode<S>(part);
cout<< "\n from root " << root->get_data();
}
else
{add(root,part);}
size++;
}
void add(BTNode<S>* node, S part)
{
S part2 = node->get_data();
cout << "part "<< part;
cout<< "part2 "<< node->get_data();
if( part == part2)
{node->set_data(part);}
else if (part > part2)
{
if (node->get_right()== NULL) //if I remove this check the segmentation error goes away
{node->set_right(new BTNode<S>(part)); cout<< "from right "<< node->right->get_data();}
else
{add(node->get_right(),part);} //If I remove the if statement above the recursion won't work
}
else
{
if (node->get_left()==NULL)
{ node->set_left(new BTNode<S>(part));}
else
{add(node->get_left(),part);}
}
}
private:
BTNode<S>* root;
BTNode<S>* current;
int size;
};
#endif
int main()
{
STree<int> trees;
trees.insert(10);
trees.insert(20);
trees.insert(30);
trees.insert(40);
return 0;
}
BS part2 = node->get_data() will access nullptr every time you insert. When implementing recursion, always take care of the base case first.
void add(BTNode<BS>* node, BS part)
{
if (part < node->get_data() && node->get_left() == nullptr)
node->set_left(new BTNode<BS>(part));
else if (part > node->get_data() && node->get_right() == nullptr)
node->set_right(new BTNode<BS>(part));
if (node->get_data() == part)
return;
else
{
if (part < node->get_data())
add(node->get_left(), part);
else
add(node->get_right(), part);
}
}
I have a set where each element in the set is of type shared_ptr, I want to remove an element from the set, in eclipse the element was actually removed but when I test this in bash with valgrind I get a lot of invalid size mistakes ...
So this made me think that maybe there is a different way to remove element of type shared_ptr ?
Every element in the peoplePointer is a class of certain person:
typedef std::shared_ptr<person> peoplePointer;
class AA {
std::set<peoplePointer> setOfPeople;
public:
// function getName() return name of the person (person is another class)
void removeSomeonefromA(const std::string& name) {
for (std::set<peoplePointer>::iterator it = setOfPeople.begin();it != setOfPeople.end(); it++) {
if(name == (*it).get()->getName()) {
setOfPeople.erase((it));
}
}
}
};
Idea inspired by remove_if equivalent for std::map.
If you are able to use a C++11 or later compiler, you can use:
void removeSomeonefromA(const string& name)
{
for (set<peoplePointer>::iterator it = setOfPeople.begin(); it != setOfPeople.end(); /* Empty */ )
{
if(name == (*it).get()->getName())
{
it = setOfPeople.erase(it);
}
else
{
++it;
}
}
}
If you are required to use a prior compiler version, you can use:
void removeSomeonefromA(const string& name)
{
for (set<peoplePointer>::iterator it = setOfPeople.begin(); it != setOfPeople.end(); /* Empty */ )
{
if(name == (*it).get()->getName())
{
setOfPeople.erase(it++);
}
else
{
++it;
}
}
}
I tried finding an answer but didn't see one for my particular problem. I am using shared pointers for a ternary search tree (to be used for a predictive text algorithm) and am running into some problems using shared pointers.
I've been away from C++ for 5 years, and let me tell you, Java does not help you learn pointers. I've had to relearn pointer material I learned in school 5-6 years ago over the past couple of days, and have successfully managed to destroy my code.
Here is most of the code I have:
// TernarySearchTree.cc
#include "stdafx.h"
#include "ternary_search_tree.h"
//Constructor
TernarySearchTree::TernarySearchTree() {
num_nodes_ = 0;
size_in_memory_ = 0;
root_node_ = nullptr;
}
TernarySearchTree::TernarySearchTree(const TernarySearchTree& other) {
num_nodes_ = other.num_nodes_;
size_in_memory_ = other.size_in_memory_;
TernarySearchTreeNode node;
node = *other.root_node_;
root_node_.reset(&node);
}
//Destructor
TernarySearchTree::~TernarySearchTree() {
}
//operators
TernarySearchTree& TernarySearchTree::operator=(const TernarySearchTree& other) {
//TODO: swap idiom - create a copy of the node then swap the new one with it
//do this first to provide exception safety
TernarySearchTreeNode node;
node = *other.root_node_;
root_node_.reset(&node);
num_nodes_ = other.num_nodes_;
size_in_memory_ = other.size_in_memory_;
return *this;
}
//Convert from string to c-style string
std::vector<char> TernarySearchTree::ConvertStringToCString(std::string str) {
std::vector<char> wordCharacters (str.begin(), str.end());
//remove newlines or tabs
if (wordCharacters.back() == '\n' || wordCharacters.back() == '\t') {
wordCharacters.pop_back();
}
wordCharacters.push_back('\0');
return wordCharacters;
}
//Insert a node
TernarySearchTreeNode TernarySearchTree::InsertNode(TernarySearchTreeNode ¤tNode,
char character,
NodePosition position,
bool isRoot) {
TernarySearchTreeNode newNode;
newNode.set_character(character);
if (!isRoot) {
switch (position) {
case NODE_POS_LEFT:
currentNode.set_left_node(newNode);
break;
case NODE_POS_CENTRE:
currentNode.set_centre_node(newNode);
break;
case NODE_POS_RIGHT:
currentNode.set_right_node(newNode);
break;
default:
break;
}
}
return newNode;
}
//Insert a word
void TernarySearchTree::InsertWord(std::string word) {
std::vector<char> characters = ConvertStringToCString(word);
std::shared_ptr<TernarySearchTreeNode> currentNode = 0;
bool isFirstCharacter = true;
//Add each character to a node while traversing
//Base case where there is no root node
if (!root_node_) {
for(std::vector<char>::iterator it = characters.begin(); it != characters.end(); ++it) {
if (*it != '\0') {
//if it is the first character
//root_node_ is equal to the address of new node
if (isFirstCharacter) {
std::cout << "HIHI";
TernarySearchTreeNode node = InsertNode(*currentNode, *it, NODE_POS_CENTRE, true);
root_node_.reset(&node);
currentNode.reset(&node);
isFirstCharacter = false;
} else {
TernarySearchTreeNode node = InsertNode(*currentNode, *it, NODE_POS_CENTRE, false);
std::cout << std::endl << node.get_character();
currentNode.reset(&node);
}
}
}
//If not base case, then we need to compare each character
} else {
currentNode = root_node_;
for(std::vector<char>::iterator it = characters.begin(); it != characters.end(); ++it) {
if (*it != '\0') {
currentNode.reset(&SetNextNode(*currentNode, *it, *std::next(it, 1)));
} else {
currentNode->set_end_of_word(true);
}
}
}
}
//Recursive function for obtaining/adding the next node when inserting a word
TernarySearchTreeNode TernarySearchTree::SetNextNode(TernarySearchTreeNode ¤tNode, const char currentChar, const char nextChar) {
//If characters match
if (currentChar == currentNode.get_character()) {
//if centre node exists
if (currentNode.get_centre_node()) {
return *(currentNode.get_centre_node());
//Otherwise, create a new node and recall method on that node
} else {
//If not the end of the word, make a new node with the next letter
if (nextChar != '\0') {
return InsertNode(currentNode, nextChar, NODE_POS_CENTRE, false);
} else {
return currentNode;
}
}
//If it is less, follow node on the left
} else if (currentChar < currentNode.get_character()) {
//if left node exists, recursive call
if (currentNode.get_left_node()) {
return SetNextNode(*(currentNode.get_left_node()), currentChar, nextChar);
//Otherwise, create a new node and recall method on that node
} else {
return SetNextNode(InsertNode(currentNode, currentChar, NODE_POS_LEFT, false), currentChar, nextChar);
}
//Otherwise it is bigger, so take right path
} else {
//if right node exists, recursive call
if (currentNode.get_right_node()) {
return SetNextNode(*(currentNode.get_right_node()), currentChar, nextChar);
//Otherwise, create a new node and recall method on that node
} else {
return SetNextNode(InsertNode(currentNode, currentChar, NODE_POS_RIGHT, false), currentChar, nextChar);
}
}
}
//Populate the TST from a word list/file
void TernarySearchTree::PopulateTreeFromTextFile(std::string fileName) {
std::ifstream file;
std::string line;
file.open(fileName);
if (file.is_open()) {
//Assume text file has one word per line
while (std::getline(file, line)) {
InsertWord(line);
}
}
}
//Search
bool TernarySearchTree::SearchForWord(std::string word) {
return false;
}
int _tmain(int argc, _TCHAR* argv[])
{
//Test
TernarySearchTree tst;
//Open file
tst.PopulateTreeFromTextFile("simple.txt");
//start at root and follow some paths
std::cout << tst.get_root_node();
/**std::vector<char> vec;
vec.push_back('a');
vec.push_back('c');
std::vector<char>::iterator it = vec.begin();
std::cout << *std::next(vec.begin(), 1);
std::cout << (*it < 'c');
it++;
std::cout << *std::next(it, 0);
std::cout << (*it < 'c');
**/
return 0;
}
and for the nodes:
/*TST node methods */
#include <iostream>
#include "ternary_search_tree_node.h"
/** ADD COPY CONSTRUCTOR*/
//Constructors
TernarySearchTreeNode::TernarySearchTreeNode() {
character_ = '\0';
end_of_word_ = false;
left_node_ = nullptr;
centre_node_ = nullptr;
right_node_ = nullptr;
}
TernarySearchTreeNode::TernarySearchTreeNode(const TernarySearchTreeNode& other) {
character_ = other.character_;
end_of_word_ = other.end_of_word_;
TernarySearchTreeNode leftNode;
leftNode = *other.left_node_;
left_node_.reset(&leftNode);
TernarySearchTreeNode centreNode;
centreNode = *other.centre_node_;
centre_node_.reset(¢reNode);
TernarySearchTreeNode rightNode;
rightNode = *other.right_node_;
right_node_.reset(&rightNode);
}
TernarySearchTreeNode::TernarySearchTreeNode(char character, bool end_of_word,
TernarySearchTreeNode left_node,
TernarySearchTreeNode centre_node,
TernarySearchTreeNode right_node) {
character_ = character;
end_of_word_ = end_of_word;
left_node_.reset(&left_node);
centre_node_.reset(¢re_node);
right_node_.reset(&right_node);
}
//Destructor
TernarySearchTreeNode::~TernarySearchTreeNode() {
left_node_.reset();
centre_node_.reset();
right_node_.reset();
}
//operators
TernarySearchTreeNode& TernarySearchTreeNode::operator=(const TernarySearchTreeNode& other) {
if (&other) {
TernarySearchTreeNode leftNode;
leftNode = *other.left_node_;
TernarySearchTreeNode centreNode;
centreNode = *other.centre_node_;
TernarySearchTreeNode rightNode;
rightNode = *other.right_node_;
left_node_.reset(&leftNode);
centre_node_.reset(¢reNode);
right_node_.reset(&rightNode);
character_ = other.character_;
end_of_word_ = other.end_of_word_;
}
return *this;
}
//printing
std::ostream& operator<<(std::ostream& os, const TernarySearchTreeNode& obj)
{
// write obj to stream
char c = obj.get_character();
bool b = obj.is_end_of_word();
os << c << "\t is end of word: " << b;
return os;
}
When I run in debug mode (Visual Studios), it is able to set the root node, but when it goes to input the second node, it crashes trying to delete "stuff" when currentNode calls .reset(&node) within the else statement of function InsertWord. Am I doing something wrong in the copy constructors or operator= methods, or the destructors? The cout line above it does print the correct letter, so it looks like the node is getting created properly.
The debug call stack shows:
TernarySearchTree.exe!std::_Ref_count_base::_Decref() Line 118 C++
TernarySearchTree.exe!std::_Ptr_base::_Decref()
Line 347 C++
TernarySearchTree.exe!std::shared_ptr::~shared_ptr()
Line 624 C++
TernarySearchTree.exe!std::shared_ptr::reset()
Line 649 C++
TernarySearchTree.exe!TernarySearchTreeNode::~TernarySearchTreeNode()
Line 50 C++ TernarySearchTree.exe!TernarySearchTreeNode::`scalar
deleting destructor'(unsigned int) C++
TernarySearchTree.exe!std::_Ref_count::_Destroy()
Line 161 C++ TernarySearchTree.exe!std::_Ref_count_base::_Decref()
Line 120 C++
TernarySearchTree.exe!std::_Ptr_base::_Decref()
Line 347 C++
TernarySearchTree.exe!std::shared_ptr::~shared_ptr()
Line 624 C++
TernarySearchTree.exe!std::shared_ptr::reset()
Line 649 C++
TernarySearchTree.exe!TernarySearchTreeNode::~TernarySearchTreeNode()
Line 50 C++
TernarySearchTree.exe!TernarySearchTree::InsertWord(std::basic_string,std::allocator
word) Line 105 C++ TernarySearchTree.exe!TernarySearchTree::PopulateTreeFromTextFile(std::basic_string,std::allocator
fileName) Line 182 C++ TernarySearchTree.exe!wmain(int argc, wchar_t * * argv) Line 200 C++
TernarySearchTree.exe!__tmainCRTStartup() Line 533 C
TernarySearchTree.exe!wmainCRTStartup() Line 377 C
kernel32.dll!7592338a() Unknown [Frames below may be incorrect
and/or missing, no symbols loaded for kernel32.dll]
ntdll.dll!77599f72() Unknown ntdll.dll!77599f45() Unknown
Thanks for any help you can provide! And let me know if there is anythign else you need me to provide (the text file I am reading in just has the word cornin it).
Your problem is that you're using Java style in C++. Unlike in Java where everything is essentially a pointer, in C++ you have to think about the difference between values, references, pointers, and object lifetime.
This function is bad:
TernarySearchTreeNode::TernarySearchTreeNode(char character, bool end_of_word,
TernarySearchTreeNode left_node,
TernarySearchTreeNode centre_node,
TernarySearchTreeNode right_node) {
character_ = character;
end_of_word_ = end_of_word;
left_node_.reset(&left_node);
centre_node_.reset(¢re_node);
right_node_.reset(&right_node);
}
You are taking TernarySearchTreeNode objects by value, then putting their address into a shared_ptr. The point of a shared_ptr to to take ownership of a dynamically allocated object (one created using new) and delete it when the reference count goes to zero. The objects above (left_node, etc) are stack objects that will go out of scope at the end of the function. When you put their address into a shared_ptr, it will then try to delete those objects later, but they no longer exist.
As far as recommending how to fix this, there is a whole lot going on here where the assumptions are just off. For instance, can a child node have more than one parent? Does it actually make sense to copy nodes?
I'll assume for the moment that copying nodes makes sense, so using shared_ptr is reasonable. In that case we might start here:
TernarySearchTreeNode TernarySearchTree::InsertNode(std::shared_ptr<TernarySearchTreeNode currentNode>,
char character,
NodePosition position,
bool isRoot) {
auto newNode = std::make_shared<TernarySearchTreeNode>();
newNode->set_character(character);
if (!isRoot) {
switch (position) {
case NODE_POS_LEFT:
currentNode->set_left_node(newNode);
Then all of your functions like set_left_node should also take std::shared_ptr<TernarySearchNode> as parameters. You should not be calling reset(), which exists to allow a shared_ptr to take ownership (refcount == 1) of a free pointer. shared_ptr works by incrementing the reference count on copy and dereferencing in the destructor. When you dereference the pointer and then take the address, you are working around the shared_ptr.
When I run my application in debug mode, sometimes I get a runtime error in this function:
void ChatListHandler::seatOccupancyChanged( const std::string& userName, bool occupied, bool isSelf, bool isSelfTable, int tableNo, int seatNo, int numPlayersAtTable )
{
if(!isSelf && (isInGroup(userName,IN_GAME_GROUP) || isInGroup(userName,IN_LOBBY_GROUP)))
{
if(occupied)
{
movePlayer(userName,IN_GAME_GROUP);
}
else
{
movePlayer(userName,IN_LOBBY_GROUP);
}
}
}
bool ChatListHandler::isInGroup( const std::string& name, GroupTypeEnum group )
{
for(size_t i = 0; i < m_groups.size(); ++i)
{
if(m_groups[i].second == group)
{
if(m_groups[i].first->getList())
{
for(agui::ListItem::iterator it =
m_groups[i].first->getList()->getItemsBegin(); it !=
m_groups[i].first->getList()->getItemsEnd(); ++it)
{
if((*it).first.text == name)
{
return true;
}
}
}
break;
}
}
return false;
m_list->repositionGroups();
}
It crashes on:
if((*it).first.text == name)
I get:
Unhandled exception at 0x5fd1942c (msvcp90d.dll) in my.exe: 0xC0000005: Access violation reading location 0x00000040.
The call stack looks like:
Thanks
I can't be sure without seeing all the code, but my guess is that there error has to do with these lines:
for(agui::ListItem::iterator it =
m_groups[i].first->getList()->getItemsBegin(); it !=
m_groups[i].first->getList()->getItemsEnd(); ++it)
Unless your call to getList() is always returning exactly the same list every time (that is, a pointer to the same list, not a copy), you could be getting iterators over different lists. This would mean that the check it != m_groups[i].first->getList()->getItemsEnd() would always be false, since the iterators come from different lists. In that case, your iterator could walk off the end of the list, so the dereference would cause a crash.
Hope this helps!