I am trying to use STL list in a project but i have the following problem.
I want my list to store a struct. For example this one
struct mystruct
{
int x;
int y;
};
Then i am using an iterator to access every struct in the list like this.
list<mystruct> L;
list<mystruct>::iterator lit;
for(lit=L.begin();lit!=L.end();lit++)
{
if(lit->x==1) cout << "<NUM," << lit->x << "> ";
if(lit->y==2) cout << "<ID," << lit->y << "> ";
}
This works but i want to get one struct at a time so i made this func
mystruct Myclass::next(void)
{
if(lit!=L.end())
{
lit++;
}
return *lit;
}
but i get an error after running it and i cannot understand why this happens.
Any ideas what is going wrong?
mystruct Myclass::next(void)
{
if(lit!=L.end())
{
lit++;
}
return *lit;
}
You increment unless you already are at the end, but the dereferencing happens every time, regardless of if you are at the end or not. To help around that problem, consider returning a pointer, and then a 0 pointer if you are at the end.
mystruct* Myclass::next(void)
{
if(lit!=L.end() && ++lit != L.end())
{
// dereference to get the struct, and then return the address of the struct
return &*lit;
}
return 0;
// or nullptr in C++0x
}
And then check agains 0 (or nullptr) in the code where you use Myclass::next.
If you're writing next() that returns an object (rather than pointer), then I think you also need to write has_next() function which you should call to inspect if there is item in the list or not, before calling next(). Something like this:
bool has_next()
{
list<mystruct>::iterator temp = lit;
return ++temp != L.end();
}
mystruct Myclass::next(void)
{
if( !has_next())
{
throw "end of the list is reached";
}
++lit;
return *lit;
}
//usage
while(myClassInstance.has_next())
{
mystruct s = myClassInstance.next();
//work with s
}
Or if you decide to return pointer to mystruct from next(), then has_next() is not so needed. You can write this:
mystruct * Myclass::next(void)
{
++lit;
if( lit == L.end() )
return NULL;
return &(*lit);
}
The problem is here :
mystruct Myclass::next(void)
{
if(lit!=L.end())
{
lit++;
}
return *lit;
}
First how is lit defined?
Second, if lit is equal to L.end() you should return some default value, not dereference it, because if you do, you are causing an undefined behaviour. If you are lucky, your program will crash.
Related
This is schoolwork. I haven't seen anything that really answers this directly, so I'm having a hard time fixing it. I have to create a linked node implementation of a max heap and I'm having difficulty with the deletion of a node after removing a value.
My Code:
template<class ItemType>
BinaryHeapNode<ItemType>* LinkedMaxHeap<ItemType>::getLastNode()
{
BinaryHeapNode<ItemType>* lastNode = rootPtr->getRightSiblingPtr();
BinaryHeapNode<ItemType>* prevLastNode = rootPtr;
while(lastNode != nullptr)
{
prevLastNode = lastNode;
lastNode = lastNode->getRightSiblingPtr();
}
return prevLastNode;
}
template<class ItemType>
bool LinkedMaxHeap<ItemType>::removeValue(ItemType value)
{
BinaryHeapNode<ItemType>* tempNode = rootPtr;
for (int i = 0; i < itemCount; i++)
{
if(tempNode->getItem() == value)
{
tempNode->setItem(getLastNode()->getItem());//set item
delete getLastNode(); //delete last node
getLastNode() = nullptr; //set last node null
getLastNode()->setRightSiblingPtr(nullptr); //last node should be different
itemCount--; //set it's sibling to null
heapRebuild(tempNode);
}
tempNode = tempNode->getRightSiblingPtr();
}
return true;
}
My issue is with getLastNode() = nullptr. VS is telling me that getLastNode() isn't an lvalue. That doesn't make sense to me because getLastNode is returning a pointer to a BinaryHeapNode, but it can't set that pointer to nullptr?
I thought this might be a problem with my logic of pointers (which is shaky at best) so I thought changing getLastNode() to return just a node would help. That did not. So I tried messing with the & operator and returning an address of the last node. Needless to say I haven't found the solution yet. If anyone can provide some sort of direction it would be appreciated. I'm just not entirely sure why it doesn't work.
EDIT:
Edited the code based on what arynaq mentioned. The errors went away, but now I have a bunch of linker errors I have to fix before I can test it. Will this code do what I want? I feel like it is just going to delete nodeToDelete and not get rid of the node in the heap.
template<class ItemType>
bool LinkedMaxHeap<ItemType>::removeValue(ItemType value)
{
BinaryHeapNode<ItemType>* tempNode = rootPtr;
BinaryHeapNode<ItemType>* nodeToDelete = getLastNode();
for (int i = 0; i < itemCount; i++)
{
if(tempNode->getItem() == value)
{
tempNode->setItem(nodeToDelete->getItem());
delete &nodeToDelete;
nodeToDelete = nullptr;
getLastNode()->setRightSiblingPtr(nullptr);
itemCount--;
heapRebuild(tempNode);
}
tempNode = tempNode->getRightSiblingPtr();
}
return true;
}
Ok, I'll try to help by explaining some things about pointers. Hopefully this will clarify some misconceptions and help you with your assignment.
When you get a copy of the pointer like so: mypointer* p = get_pointer(); and then you delete that, you are deleting the memory. But when you assign nullptr to this local variable, it wont affect the "source" of your pointer.
Here is a detailed example, showing where things can go wrong. If you never set v[0] to nullptr.
#include <iostream>
#include <vector>
struct Object {
~Object() {
std::cout << "Object destructor." << std::endl;
}
int val = 42;
};
struct OtherObj {
int val = 322;
};
void print_vec(const std::vector<Object*>& v) {
for (const auto& x : v) {
std::cout << x << std::endl;
}
}
int main(int, char**) {
// Init vector and print addresses.
std::vector<Object*> v(2);
print_vec(v);
// Init objects in vector and printit.
for (auto& x : v) {
x = new Object();
}
print_vec(v);
// Get a copy of a pointer and delete that. All good so far.
Object* pointer_to_delete = v[0];
delete pointer_to_delete;
// Assign nullptr to the temporary local pointer.
// Does nothing to the pointer in the vector.
pointer_to_delete = nullptr;
// Print the vector to prove it.
print_vec(v);
// On a non debug build, the memory will still have the last value.
// Careful! Cause of headaches here. This should be set to nullptr.
std::cout << v[0]->val << std::endl; // "No problem", certainly not nullptr.
// Now that we allocate a new object, v[0] will be overwritten.
OtherObj* bad_bad_boy = new OtherObj();
// Print the address of the new object, to show it was created at
// the old v[0] address.
std::cout << bad_bad_boy << std::endl;
// Bad things ensue...
std::cout << v[0]->val << std::endl;
return 0;
}
The output on clang is :
0x0
0x0
0x7ffa21c026c0
0x7ffa21c026d0
Object destructor.
0x7ffa21c026c0
0x7ffa21c026d0
42
0x7ffa21c026c0
322
As you can see, setting the local pointer to nullptr is not enough! I hope this clears up some things for you :)
Online version
I'm new to C++, sorry if it's a dummy question.
I'm trying to create a method that would remove a given pointer from a vector, and delete its object. Here's what I have right now:
void Engine::destroyObject(GameObject* obj) {
if (obj == nullptr) {
std::cout << "Error: GameObject pointer given is null!" << std::endl;
return;
}
else if (m_GameObjects.empty()) {
std::cout << "Error: Trying to destroy GameObject while list is empty!" << std::endl;
return;
}
auto it = std::remove(m_GameObjects.begin(), m_GameObjects.end(), obj);
if (it != m_GameObjects.end()) {
delete obj;
m_GameObjects.erase(it, m_GameObjects.end());
}
}
GameObject* Engine::findObject(std::string name) {
return *std::find_if(m_GameObjects.begin(), m_GameObjects.end(), [name](GameObject* e) { return e->getName() == name; });
}
I'm calling those methods like this:
GameObject* obj = findObject("Random");
destroyObject(obj);
But for some reason, my program crashes at m_GameObjects.erase(it, m_GameObjects.end()); with the error "vector iterator not dereferencable"
I have tried changing the line to it = m_GameObjects.erase(it, m_GameObjects.end()); but that did not change anything.
Thanks in advance!
Edit: Here's a bit more info
GameObject is just a regular class (with some data such as a name...)
The findProject method works fine, it's the line for erase that's causing an error.
So aschepler found out that my findObject function was not checking for null values (if the object didn't exist/couldn't be found) so I added some checks and it works now. Thanks a lot!
GameObject* Engine::findObject(std::string name) {
auto it = std::find_if(m_GameObjects.begin(), m_GameObjects.end(), [name](GameObject* e) { return e->getName() == name; });
if (it == m_GameObjects.end())
return nullptr;
return *it;
}
I then had to check if the value was a nullptr and not do anything if so.
I have an open hash table using the STL.
typedef std::list<int> LIST;
typedef std::vector<LIST> HASH_TABLE;
I initialized the hash table by filling it with empty lists.
LIST mt_list;
HASH_TABLE hTable;
hTable.assign(7, mt_list);
Now if I want to add an int to my table based on:
hKey = (value*value) % 7;
and I use
hTable[hKey].push_back(value);
It should work right? I can't get it to work.
void addValue(int value){
if(val_find(value)){
std::cout << "WARNING: duplicate input: " << value << std::endl;
}
else{
calc_hash_bucket(value); //set hKey
hTable[hKey].push_back(value); //push value into list
}
}
The code above does not add the element to any of the lists within the vector.
Also, when I want to use an iterator to traverse the vector and the lists within the vector, how do I get one element at a time from a list so I can find a particular value that may or may not already be in the list?
This is what I have for finding a value within the hash table:
bool val_find(int value){
if(mt_hash()){
return false;
}
else{
for(HASH_ITER h_iter = hTable.begin(); h_iter != hTable.end(); ++h_iter){
for(LIST_ITER l_iter = h_iter->begin(); l_iter != h_iter->end(); ++l_iter){
if(*l_iter == value){
return true;
}
}
}
}
return false;
}
I'm stumped. I don't understand why it won't add the value to any of the lists.
I feel I should mention this is all in a header file and part of a class that I created. (I don't know if that matters)
Edit: The warning statement does not print. To answer questions, the mt_hash() function checks to see if the hash table is empty and I have checked it several times to make sure it outputs correctly. I fixed the hTable_1 vs hTable difference, they are the same thing. I just forgot to change it when I put it into the question.
bool mt_hash(void){ //is hash table empty?
for(unsigned int i = 0; i < hTable.size(); ++i){
if(!hTable.at(i).empty()){ //if not empty return false
return false;
}
}
return true; //else return true
}
Thanks,
Zach
As Pradhan points out, there is a quite a bit missing. What is the implementation of mt_hash()? Are hTable_1 and hTable the same object?
Below, I've taken your code above, and placed them in a struct with the implied functionality included. Note three changes: hTable replaces hTable_1 in val_find(); addValue() uses a local variable to store the hash key; and mt_hash() is implemented by keeping a simple element count.
#include <list>
#include <vector>
#include <iostream>
#include <iomanip>
struct open_hash {
typedef std::list<int> LIST;
typedef std::vector<LIST> HASH_TABLE;
typedef LIST::const_iterator LIST_ITER;
typedef HASH_TABLE::const_iterator HASH_ITER;
HASH_TABLE hTable;
int nbins;
int elem_count;
explicit open_hash(int nbins_): nbins(nbins_), elem_count(0) {
init_hash();
}
void init_hash() {
LIST mt_list;
hTable.assign(nbins, mt_list);
}
int hash_bucket(int value) const {
return (value*value)%nbins;
}
bool mt_hash() const {
return elem_count==0;
}
bool val_find(int value) const {
if (mt_hash()) {
return false;
}
for (HASH_ITER h_iter = hTable.begin(); h_iter != hTable.end(); ++h_iter){
for (LIST_ITER l_iter = h_iter->begin(); l_iter != h_iter->end(); ++l_iter){
if (*l_iter == value) {
return true;
}
}
}
return false;
}
void addValue(int value) {
if (val_find(value)) {
std::cout << "WARNING: duplicate input: " << value << std::endl;
}
else {
int hKey=hash_bucket(value);
hTable[hKey].push_back(value); //push value into list
++elem_count;
}
}
};
int main() {
open_hash H(7);
std::vector<int> vals={3,1,9,2,10,4,3};
for (int v: vals) {
H.addValue(v);
}
for (int i=1; i<=10; ++i) {
std::cout << "val_find(" << i << "):\t" << std::boolalpha << H.val_find(i) << "\n";
}
}
This produces expected output:
WARNING: duplicate input: 3
val_find(1): true
val_find(2): true
val_find(3): true
val_find(4): true
val_find(5): false
val_find(6): false
val_find(7): false
val_find(8): false
val_find(9): true
val_find(10): true
I suspect the original problem lies in addValue() and val_find() referring to different hash objects, or a problem in mt_hash() misreporting that the table is empty when in fact it is not.
The answer to the this problem is to create the class object of type HASH_TABLE in the main cpp file and then pass it by reference into the function (getCmd) that calls all of the commands and i/o.
I was calling the "getCmd" function in main() and that function (EVERY time it is called) creates a NEW instance of the HASH_TABLE class, effectively "replacing" the previous object with a new, empty object. (though I suspect it did not actually replace the previous object. I think the previous object was still taking up memory but it was not being used)
I didn't post the code for the problem area because I didn't know where the problem was.
Thanks for all your help!
I am currently working on a bit of code that will search within a vector of type Person (which I have defined in the code and will show if needed). If it finds the person, it returns their name. This is currently working, but if it does not find the person, it is supposed to return a Null pointer. The problem is, I cannot figure out how to make it return a Null pointer! It just keeps either crashing the program every time.
Code:
Person* lookForName(vector<Person*> names, string input)
{
string searchName = input;
string foundName;
for (int i = 0; i < names.size(); i++) {
Person* p = names[i];
if (p->getName() == input) {
p->getName();
return p; //This works fine. No problems here
break;
} else {
//Not working Person* p = NULL; <---Here is where the error is happening
return p;
}
}
}
You could use std::find_if algorithm:
Person * lookForName(vector<Person*> &names, const std::string& input)
{
auto it = std::find_if(names.begin(), names.end(),
[&input](Person* p){ return p->getName() == input; });
return it != names.end() ? *it : nullptr; // if iterator reaches names.end(), it's not found
}
For C++03 version:
struct isSameName
{
explicit isSameName(const std::string& name)
: name_(name)
{
}
bool operator()(Person* p)
{
return p->getName() == name_;
}
std::string name_;
};
Person * lookForName(vector<Person*> &names, const std::string& input)
{
vector<Person*>::iterator it = std::find_if(names.begin(), names.end(),
isSameName(input));
return it != names.end() ? *it : NULL;
}
If the name you are searching for is not at the first element, then you are not searching in the rest of the elements.
You need to do something like -
for (int i = 0; i<names.size(); i++){
Person* p = names[i];
if (p->getName() == input) {
return p;
// Placing break statement here has no meaning as it won't be executed.
}
}
// Flow reaches here if the name is not found in the vector. So, just return NULL
return NULL;
As Chris suggested, try using std::find_if algorithm.
Looks like you just have to return Null, nullptr, or 0.
codeproject
Just use following code:
return NULL;
I'm getting some weird behavior with a vector in C++ I was hoping someone could help me out. I have a vector like so:
vector<Instruction*> allInstrs;
the struct for Instruction is as follows:
struct Instruction : simple_instr
{
InstrType type;
Instruction(const simple_instr& simple) : simple_instr(simple)
{
type = Simple;
loopHeader = false;
loopTail = false;
}
int Id;
bool loopHeader;
bool loopTail;
};
the problem I'm having is this:
I need to iterate through each instruction and pull out specific fields and use those to do some analysis on the instructions in the vector. To do that, I was basically doing
VariableList Variables;
void GenerateVariableList()
{
for (int i = 0; i < allInstrs.size(); i++)
{
Variables.Add(allInstrs[i]);
}
Variables.RemoveDuplicates();
}
Variable List is defined as
struct VariableList
{
void Add(simple_instr* instr)
{
PrintOpcode(instr);
switch(instr->opcode)
{
case STR_OP:
case MCPY_OP:
Add(instr->u.base.src1);
Add(instr->u.base.src2);
break;
case LDC_OP:
Add(instr->u.ldc.dst);
break;
case BTRUE_OP:
case BFALSE_OP:
Add(instr->u.bj.src);
break;
case CALL_OP:
cout << "CALL OP" <<endl;
break;
case MBR_OP:
Add(instr->u.mbr.src);
break;
case RET_OP:
if (instr->u.base.src1 != NO_REGISTER)
Add(instr->u.base.src1);
break;
case CVT_OP:
case CPY_OP:
case NEG_OP:
case NOT_OP:
case LOAD_OP:
Add(instr->u.base.dst);
Add(instr->u.base.src1);
break;
case LABEL_OP:
case JMP_OP:
break;
default:
Add(instr->u.base.dst);
Add(instr->u.base.src1);
Add(instr->u.base.src2);
break;
}
}
void Add(Variable var)
{
variableList.push_back(var);
}
void RemoveDuplicates()
{
if (variableList.size() > 0)
{
variableList.erase(unique(variableList.begin(), variableList.end()), variableList.end());
currentID = variableList.size();
}
}
VariableList()
{
currentID = 0;
}
VariableList(VariableList& varList, bool setLiveness = false, bool LiveVal = false)
{
currentID = 0;
for (int i = 0; i < varList.size(); i++)
{
Variable var(varList[i]);
if (setLiveness)
{
var.isLive = LiveVal;
}
variableList.push_back(var);
}
}
Variable& operator[] (int i)
{
return variableList[i];
}
int size()
{
return variableList.size();
}
vector<Variable>::iterator begin()
{
return variableList.begin();
}
vector<Variable>::iterator end()
{
return variableList.end();
}
protected:
int currentID;
vector<Variable> variableList;
void Add(simple_reg* reg, bool checkForDuplicates = false)
{ cout << "Register Check" <<endl;
if (reg == null)
{
cout << "null detected" << endl;
return;
}
if (reg->kind == PSEUDO_REG)
{
if (!checkForDuplicates || (checkForDuplicates && find(variableList.begin(), variableList.end(), reg->num) != variableList.end()))
{
cout << "Adding... Reg " << reg->num << endl;
Variable var(reg->num, currentID);
variableList.push_back(var);
currentID++;
}
}
}
};
When I do this though, every instruction goes to the default case statement, even though I knwo for a fact some instructions shouldn't. If I change GenerateVariableList to
void GenerateVariableList()
{
for (int i = 0; i < allInstrs.size(); i++)
{
PrintOpcode(allInstrs[i]);
Variables.Add(allInstrs[i]);
}
Variables.RemoveDuplicates();
}
so that there is now a second PrintOpCode in addition to the one in Variables.Add, the program behaves correctly. I can't understand why adding a second PrintOpcode makes it work correctly. All print Opcode is is a function with a switch statement that just prints out a specific string depending on what the value of one of simple_instr's fields is.
VariableList Variables is contained inside of a separate struct called CFG
If you need more information/code i can provide it. If the answer is obvious I apologize, I don't program in C++ very often
EDIT:
One of the answers left, deleted now though, got me the fix.
Previously I was doing
static vector<Instruction*> ConvertLinkedListToVector(simple_instr* instructionList)
{
vector<Instruction*> convertedInstructions;
int count = 0;
for (simple_instr* current = instructionList; current; count++, current = current->next)
{
//Instruction* inst = new Instruction(*current);
Instruction inst = Instruction(*current);
inst.Id = count;
convertedInstructions.push_back(&inst);
}
return convertedInstructions;
}
to make the vector, but after reading that answer I changed it back to using "new" and it works correctly now. Thanks for the help, sorry for the dumb question heh
Most likely the const simple_instr& simple passed to your constructor goes out of scope, and you keep an invalid reference/pointer to a simple_instr.
Possibly not related your problem, but certainly a potential source of strange behaviour: Your Instruction(const simple_instr& simple) constructor may be getting called when you don't intend it. Mark it explicit...
explicit Instruction(const simple_instr& simple) ...
If that causes compiler errors, then that's progress :-) You might need to write a copy constructor to make them go away, and explicitly call the old constructor where you need to.
So, there are several suspicious observations:
In your definition of VariableList you use a type called Variable - how is that type defined?
Iterating over a container should be done using an iterator:
for (vector<Intruction *>::iterator it = allInstrs.begin();
it != allInstrs.end();
++it) {
Variables.Add(*it);
}
You should consider using a vector of boost::shared_ptr, or a boost::ptr_vector instead of a vector of pointers.
I can give you a huge general overview of "don'ts" relating to your code.
You are right in this case to use classes "deriving" from simple_instr but you are doing it wrong, given that later on you do a switch statement based on type. A switch-statement based on type (rather than state) is an anti-pattern. You should be calling some virtual method of your base class.
You almost certainly do not want your derived class to copy from the base class. You want to construct it with the parameters to construct its base-class.
You want a vector of the base class pointers? And to manage lifetime probably shared_ptr
const-correctness. Some of your methods like size() should certainly be const. For others you might want two overloads.