While writing code for my assignment, I have stuck on one strange behavior. The code is big, so while it is not necessary, I won't post it.
The thing is while I was trying to delete an object from the vector, I had a segmentation fault. While trying to debug it myself, I have found this:
If I execute my code with the following snippet, I have my vector empty and then segmentation fault on the second line (since vector is empty).
cout << this->adjacencyList.empty() << endl; // yeah, I'm working with graph
cout << *(this->adjacencyList[0]) << endl; // list has pointers
However, when I delete the second line, it shows that vector is not empty and then proceeds.
The guard for empty vectors cannot hold it and segmentation fault comes.
Do you have any ideas on this behavior? If the point is still vague, I can post my full code as an edit.
Thanks in advance.
EDIT:
For the one who was asking "a little more".
void Node :: removeEdge (string destination) // removes an edge; edge is a class that contains a pointer to another node and its weight
{
bool deleted = false;
cout << *this << endl; // output stream operator is overloaded for node class and is working properly - shows it's label and edges - no error for an edge
cout << this->adjacencyList.empty() << endl;
// cout << *(this->adjacencyList[0]) << endl; // output stream operator is overloaded for edge class - error for an edge
if (!this->adjacencyList.empty())
{
for (vector <Edge *> :: iterator itr = this->adjacencyList.begin(); itr != this->adjacencyList.end(); ++itr)
{
if (((*itr)->getAdjacent())->getLabel() == destination) // segfault here
{
Edge *temp = *itr;
this->adjacencyList.erase (itr);
delete temp;
deleted = true;
}
}
}
if (!deleted)
throw EDGE_DOES_NOT_EXIST; // one of exceptions declared in enum somewhere in my code
}
SECOND EDIT:
NOTE: I cannot change headers (they were supplied by assistants), so don't ask me to change.
If you are interested in a full code, you can find here
http://pastebin.com/iCYF6hdP - Exceptions.h - all exceptions
http://pastebin.com/1fcgHGDa - Edge.h - edge class declaration
http://pastebin.com/C2DD6e3D - Edge.cpp - edge class implementation
http://pastebin.com/ZNqQ1iHE - Node.h - node class declaration
http://pastebin.com/kaVtZ3SH - Node.cpp - node class implementation
http://pastebin.com/A7Fwsi4m - Network.h - graph class declaration
http://pastebin.com/02LX0rjw - Network.cpp - graph class implementation
http://pastebin.com/MRMn0Scz - main.cpp - sample main
I would guess, that the pointer stored in the first element of your vector is invalid (perhaps NULL?).
So the segfault doesn't come up in this->adjacencyList[0] but in *(some_invalid_pointer).
Try
Edge* firstEdge = this->adjacencyList[0];
cout << *firstEdge << endl;
to verify this.
EDIT
If the segfault happens in the first statement (the assignment), this means, that either this is invalid or you somehow managed to corrupt memory belonging to the internals of vector. For this to verify, we would have to see all code that deals with your adjacencyList (and I'm not sure if SO people have the time for this task ...)
Note
I've spotted a bug in the removeEdge, which is not directly related to your problem. Within the loop, you use vector::erase to delete the current element. This invalidates all iterators beyond the current one, so theoretically the rest of the loop is the infamous 'undefined behavior'(TM). In this specific case (and supposing a 'normal' standard library), this will not result in a segfault but you might miss some elements:
If you delete the current element, the current iterator (normally simply a pointer) will point to the next element. Then, the loop increment will move it to the element after this one resulting in one element not being checked.
If you have similar bugs in your code in other places, this might well result in memory corruption.
Tip
If you're using Microsoft C++, you can enable checked iterators (see here). These might be able to spot this kind of bugs in your code.
2nd EDIT (in response to code)
You have a serious error in the Node::operator+.
Node &operator+ (Node &l, Node &r) // merges two nodes - for network merging
{
Node newNode (l.label);
// Doing something
return newNode;
}
That means, you're returning a reference to a local variable, never do that :) ...
Note that, since you're using a vector of pointers, which are managed separately and released in the destructor, you cannot simply change the signature to Node operator+(...: in this case, the standard copy constructor would be called, which would simply copy all pointers to the result object. Then, the destructor of the local object would be called which would invalidate all pointers.
To fix this, you should implement a copy constructor on Node which makes real copies of all edges in the adjacency list.
Alternatively, you could use smart pointers (either auto_ptr resp. unique_ptr or shared_ptr) for the list.
Or you change the merge function to something like Node::mergeFrom(Node& node2) instead of overloading the +operator.
Concerning the original problem, you can easily end up working on an invalid Node instance using your current code (so the *this-Pointer would be invalid inside removeEdge)
Related
I have to write a function that erases an element out of the list if it's bigger than the previous element.(The previous element is the one which points to the next element before deletion)
I think I've basically finished it but I don't know why it doesn't erase 5 out of my list.
void deleteBigger(list<int> s){
list<int>::iterator test;
for(test = s.begin(); test != s.end(); test++){
int sk1=*test;
cout<<sk1<<endl;
test--;
int sk2=*test;
cout<<sk2<<endl;
if(sk1>sk2){
cout<<"Im here!\n";
s.erase(test);
}
test++;
}
}
It doesn't give an error or anything it just doesn't erase. I tried to test the erase method in the main function of the program, and there it worked fine.
There are three problems with your code:
Your list is passed by value, not reference. So you are changing a copy of your list and it doesn't alter the original container
You try to remove an element from a list while iterating it. Edit: As #Remy Lebeau mentioned in the comments, to be more precise it's a problem because you don't update the iterator properly, but not a problem on its own. Be advised, that when you remove an element from a list, the iterator which pointed to the erased element is considered invalidated.
Upon the first iteration, you decremented the iterator out of the container's bounds
Summing it up, what you might want to have here looks something like this:
void deleteBigger(std::list<int> &s) {
using namespace std;
if (s.empty()) {
return;
}
for(auto test = next(s.cbegin()); test != s.cend(); ++test){
while ((*test > *prev(test)) && (test != s.cend())) {
test = s.erase(test);
}
}
}
I've copied your code and it doesn't work. The problem is your iterator pointer "test". You can't degree a pointer at the begin. The only thing you can do is use a control.
Note: it's wrong decrement a pointer because you are decrementing of (32 bits) the index of memory. In this case there is overriding -- operator that saves your program but be careful next times
Control your program. It's important use a debugger editor where you can stop the program at certain point and control the value of the variables
I made a doubly linked list. In my main, I need to use an external List Iterator that has a constructor that takes a list. This is what I have so far:
struct ListIterator : List {
Node* cur = head;
ListIterator(List* list) {
this -> list = list;
}
bool hasNext() {
return (cur -> next) != nullptr;
}
int next() {
return list.at(cur -> next);
}
};
This is my main:
List list1;
list1.append('I');
list1.append('D');
list1.append('F');
list1.append('G');
ListIterator it(list1);
while (it.hasNext()) {
cout << it.next();
}
As you can see, I'm trying to use hasNext() and next() to display all the nodes in a list. I'm confused on how to create a constructor that takes a list and use the function in ListIterator struct. Any tips and hints would be very much appreciated.
You seem to be heavily influenced by Java (or perhaps even C#). It's not a bad thing, you just need to learn the ins and outs of C++.
For your first problem: in C++, there is a clear distinction between values, references and pointers. When you declare an instance of your List class as follows:
List list1;
that is actually a value. The instance exists on the stack and will be properly disposed off (the destructor will be called) once the scope is ended.
If you now were to initialize a second list as follows:
List list2 = list1;
that is also a value, and it will copy the entire list (the copy constructor or assignment operator will be called). Now list1 and list2 are two distinct list instances and modifying one will not affect the other.
Anyhow, to get a pointer to a list, you need the following syntax:
List *listPtr1 = &list1;
As it is a pointer, an indirection, copying it will not copy the underlying structure:
List *listPtr2 = listPtr1; // Will also point to list1
While using the proper syntax will solve your immediate problem, it doesn't properly address the odd iterator implementation.
In C++, iterators either point to a single element in a container or they point past-the-end. An iterator typically does not know if the end of the container is reached by itself; instead, it needs to be compared to this past-the-end iterator.
Containers typically define a begin method that returns an iterator to the first element, and an end method that returns an iterator to past-the-end.
Iterating over a container typically happens using the following prototype:
for (auto it = container.begin(); it != container.end(); ++it)
{
// To access the element, you need to dereference the iterator:
std::cout << "The current value is :" << *it << std::endl;
}
In this regard, iterators behave much like pointers to the elements. There's no need for the clunky next and hasNext methods. You simply get an iterator to the start of your container, make sure to stop iterating once it points to past-the-end, and increment it when you want to go to the next element.
A container that properly defines the begin and end methods can also be used in a range-based for loop:
for (auto &element : container)
{
std::cout << "The current value is :" << element << std::endl;
}
I understand it is fun and very educational to implement your own containers. I reinvented my fair share of wheels just to understand how things work exactly, so nothing wrong with that. But I would advice you to perhaps play around with standard C++ containers first, get the hang of the major differences between C++ and languages like Java and C# and then have another go at the exercise.
Whenever I call dominoes.erase() which is of type std::vector<Domino> I get a segmentation fault; even if I hard code the value.
A separate member function calls dominoes.push_back() to load data and I'm able to use pop_back() to remove and return the a domino from the vector, so I know there's data in there. I've got a copy constructor made on the Domino object and that works just fine. I've narrowed it down to dominoes.erase().
Domino::Domino( const Domino &d ) {
left = d.getHighPip();
right = d.getLowPip();
}
Domino DominoCollection::drawDomino( void )
{
int index = random.nextNumber( dominoes.size() );
Domino d( dominoes[index] );
dominoes.erase( dominoes.begin() + index );
return Domino( d );
}
Any help would be greatly appreciated. Thanks!
Try to narrow down the error by removing all unnecessary code (object copy, vector access...). Then if the problem really comes from erase, add guards to be sure the indexes are right. Try again with this code:
#include <cassert>
void DominoCollection::drawDomino( void )
{
assert(dominoes.size() != 0 && "Your vector is empty");
int index = random.nextNumber( dominoes.size() );
assert(index < dominoes.size() && "Buffer overflow...");
dominoes.erase( dominoes.begin() + index );
}
If it still segfaults, the problem comes from the destructor of the class Domino. Look if there is anything fishy there. You can do quick tests by commenting parts of the destructor (or all of it), to know where the problem comes from. Calling erase will call the destructor of Domino.
If the destructor is not implemented, it might be a good idea to implement one with an output in it (on cerr, not cout) to know if it gets there or crashes earlier on. Is Domino a derived class? Does it have any other objects in it or only a composition of primitive types?
Edit
I went through your code quickly: the problem comes from the assignment operator:
Domino & Domino::operator = ( const Domino & d )
{
*this = d;
}
This is NOT how it should be written... I let you debug that as an exercise.
As for why that is the source of the bug: you said erase crashed but not pop_back. The main difference between the two (implementation difference, not the obvious semantic difference) is that erasing causes all the elements to shift after the ones deleted (using the = operator) because std::vector requires the elements to be stored consecutively. Whereas pop just changes the tail pointer and does not alter the rest of the container.
From what you show us, it looks like the int index has a value greater than or equal to dominoes.size(). Otherwise, that code would work just fine.
I'd check what random.NextNumber(dominoes.size()) returns.
Also, this problem could occur if dominoes.size() == 0. In that case, you'd be erasing dominoes.end().
I was working on a C++ project with visual studio 2010 and everything was fine but when i tried to run my program with xcode 4 it raises Bas_Access exception. I think it's because of a memory leak but I'm not sure about how to solve the problem.
I have the following function:
// Search is my class with x and y as members and here's is a constructor
// that I cretae in my Search.cpp class
Search& Search::operator=( const Search& search )
{
if(this != &search)
{
x = search.x;
y = search.y;
}
return *this;
}
And here is how my function is called:
Search searchStart(0,0);
//I created my tempSearch and initialized it with the start Search element
Search tempSearch(searchStart);
//bestSolution is a function that calculates the best neighbour node around the searchStart node, it returns a Search element. And stores it in a list in storage.
Search * tempCurrent=searchStart.bestSolution(&storage);
//Here I call my function
tempSearch=*tempCurrent;
I'm simply creating a new Search element from an existing element but it gives me exception at
x=search.x;
It works perfectly with visual studio.
EDIT:
I just added the code where my function is called. Excuse me for not being able to provide the full code because it's really long.
EDIT:
Here's my bestSolution function:
Search * searchNode::Search::bestSolution(Storage *storage )
{
//listResult is a type defined as std::list<Search *> listResult.
listResult::iterator it, it1;
listResult tempList;
//I've initialized the result element at (0,0) because it was creating problems
// if uninitialized
Search *result=new Search(0,0);
//openList is a simple list of Search elements
if(!storage->openList.empty()){
for(it=storage->openList.begin();it!=storage->openList.end();it++)
{
tempList.push_back((*it));
}
tempList.reverse();
it1=tempList.begin();
// getDistanceCost is a function that calculates the heuristic distance
// between two points and works fine
int fCost=(*it1)->getDistanceCost();
for(it1=storage->openList.begin();it1!=storage->openList.end();it1++)
{
if((*it1)->getDistanceCost()<=fCost){
fCost=(*it1)->getDistanceCost();
result=(*it1);
}
}
}
return result;
}
My guess is that bestSolution is returning a pointer to an object allocated on stack. Now when you try to tempSearch=*tempCurrent you are trying to copy values into this invalid pointer which causes the undefined behavior.
EDIT
Looking at the implementation of the bestSolution method, I assume listResult contains Search* as its nodes as you are doing result=(*it1);. It looks like the Search object to which the list has a pointer was deleted after it was inserted into the list. So what you have in the list is an invaid pointer. If you try to copy anything to the memory pointed by this invalid pointer, your program will behave unpredictably.
Given the information you provided it is certain that the problem lies in
Search * tempCurrent=searchStart.bestSolution(&storage);
It must return some invalid pointer (perhaps NULL).
This invalid pointer is then passed as the search parameter (more precisely as &search) to your Search::operator= which then tries to access the x (and later the y) member of this invalid pointer (search.x and search.y).
This is the first part of a function I have that's causing my program to crash:
vector<Student> sortGPA(vector<Student> student) {
vector<Student> sorted;
Student test = student[0];
cout << "here\n";
sorted.insert(student.begin(), student[0]);
cout << "it failed.\n";
...
It crashes right at the sorted part because I can see "here" on the screen but not "it failed." The following error message comes up:
Debug Assertion Failed!
(a long path here...)
Expression: vector emplace iterator outside range
For more information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.
I'm not sure what's causing the problem now, since I have a similar line of code elsewhere student.insert(student.begin() + position(temp, student), temp); that does not crash (where position returns an int and temp is another declaration of a struct Student). What can I do to resolve the problem, and how is the first insert different from the second one?
It should be:
sorted.insert(sorted.begin(), student[0]);
You were passing the iterator from the wrong instance.
When you use std::vector::insert ( iterator position, const T& x );, the iterator position must point into that same vector. You're using an iterator from student with sorted.insert, which dies.