I am trying to return the root node of a BST. My recursive function involves using std::vector as a container for SPnodes (the tree node object) which during a single call is iterated over and a vector with fewer elements is passed up to the next call. Once the vector is of size 1, my function returns a new SPnode which is created by calling the copy constructor on the first (and only) element in nodeList, the vector container.
This is then passed through the wrapper function and then to the original caller.
Question
I understand that when the vector container goes out of scope it is destroyed, however I'm allocating new memory and copying the SPnodes so I don't understand how this could be causing the problem. So then, what is causing this? I doubt my problem is unique, but I can't seem to find an answer after going through countless SO questions.
Code
SPnode header:
#ifndef SPNODEOBJ_H
#define SPNODEOBJ_H
#include "IntervalObjects.h"
#include "IntervalObj.h"
#include "InVecObj.h"
#include "StandardLib.h"
// --- SPnode Class ------------------------------------------------------------
// SPnode (or Subpaving Node), is a node in a binary tree which contains a
// parameter "box" which is an InVec object, and a left and right child which
// are also SPnode objects. These SPnode objects are the resultant boxes from
// calling the expand method on m_box. This implementation allows for two
// important characteristics: there is a way to determine "where" a given box in
// a subpaving is by iterating over a node's left or right child, which in turn
// allows for greater efficiency; secondly, the tree structure gives a "history"
// of the subpaving, which allows for the determination of parent boxes.
class SPnode
{
private:
InVec m_box;
// left and right children of this SPnode object - note that these must be
// pointers in order to use them in the definition of the class, otherwise
// SPnode would reference itself in its definition
SPnode* m_left;
SPnode* m_right;
// a boolean sepcifying whether the SPnode m_box is in the given subpaving
bool m_inSP;
bool m_hasBeenIterated;
public:
SPnode(InVec box): m_box(box), m_left(NULL), m_right(NULL), m_inSP(true),
m_hasBeenIterated(false) {}
SPnode(const SPnode &ASP)
{
recConstructor(this, ASP);
}
void recConstructor(SPnode* const &parent, const SPnode &ASP);
void recDestructor(SPnode* const &ASP);
~SPnode() {delete m_left;
delete m_right;}
// getters and setters
InVec getBox() const {return m_box;}
SPnode* getLeft() const {return m_left;}
SPnode* getRight() const {return m_right;}
bool getInSP() const {return m_inSP;}
bool getIterated() const {return m_hasBeenIterated;}
void setBox(const InVec box) {m_box = box;}
void setLeft(SPnode* const p_node) {m_left = p_node;}
void setRight(SPnode* const p_node) {m_right = p_node;}
void setInSP(bool truth) {m_inSP = truth;} // when this is called truth
// should only be false
void setIterated(bool truth) {m_hasBeenIterated = truth;}
bool isLeaf() const;
friend std::ostream& operator<< (std::ostream &out, const SPnode &ASP);
SPnode operator=(const SPnode& ASP)
{
std::cout << "assignment called\n";
if (this == &ASP) return *this;
recConstructor(this, ASP);
return *this;
}
friend void expand(SPnode &ASP);
friend InVec lower(const InVec &box, const Interval &width, int axis);
friend InVec upper(const InVec &box, const Interval &width, int axis);
friend void mince(SPnode &ASP);
friend SPnode regularize(ImList &list, InVec box);
friend SPnode* recRegularize(std::vector<InVec> &list, SPnode &parentNode);
};
#endif
SPnode cpp file:
#include "SPnodeObj.h"
void SPnode::recConstructor(SPnode* const &parent, const SPnode &ASP)
{
parent->m_box = ASP.m_box;
parent->m_inSP = ASP.m_inSP;
parent->m_hasBeenIterated = ASP.m_hasBeenIterated;
if (ASP.isLeaf())
{
parent->m_left = NULL;
parent->m_right = NULL;
return;
}
if (ASP.m_left == NULL)
{
parent->m_left = NULL;
}
if (ASP.m_right == NULL)
{
parent->m_right = NULL;
}
if (ASP.m_left != NULL)
{
parent->m_left = new SPnode((ASP.m_left)->m_box);
}
if (ASP.m_right != NULL)
{
parent->m_right = new SPnode((ASP.m_right)->m_box);
}
if (ASP.m_left != NULL)
{
recConstructor(parent->m_left, *(ASP.m_left));
}
if (ASP.m_right != NULL)
{
recConstructor(parent->m_right, *(ASP.m_right));
}
}
bool SPnode::isLeaf() const
{
return (m_left == NULL && m_right == NULL);
}
std::ostream& operator<< (std::ostream &out, const SPnode &ASP)
{
if (ASP.m_right == NULL && ASP.m_left != NULL)
{
out << "SPnode(SPnode, " << ASP.m_box << ", NULL)";
}
else if (ASP.m_left == NULL && ASP.m_right != NULL)
{
out << "SPnode(NULL, " << ASP.m_box << ", SPnode)";
}
else if (ASP.m_left == NULL && ASP.m_right == NULL)
{
out << "SPnode(NULL, " << ASP.m_box << ", NULL)";
}
else
{
out << "SPnode(SPnode, " << ASP.m_box << ", SPnode)";
}
return out;
}
and my functions:
SPnode* listToTree (std::vector<InVec> boxList)
{
int counter = 0;
std::vector<SPnode> nodeList;
for (auto box : boxList)
{
nodeList.push_back(SPnode(box));
counter += 1;
}
//return recListToTree(nodeList);
//return new SPnode(*(recListToTree(nodeList)));
return recListToTree(nodeList);
}
SPnode* recListToTree (std::vector<SPnode> &nodeList)
{
std::cout << "nodelist size is: " << nodeList.size() << "\n";
if (nodeList.size() == 1)
{
return new SPnode(nodeList.at(0));
}
std::vector<SPnode> parentNodeList;
int counter = 0;
for (auto node : nodeList)
{
if (node.getIterated())
{
counter += 1;
continue;
}
if (counter + 1 == nodeList.size())
{
parentNodeList.push_back(SPnode(node.getBox()));
break;
}
if (node.getBox().isAdjacent(nodeList.at(counter + 1).getBox()))
{
SPnode newNode =
SPnode(node.getBox().combine(nodeList.at(counter + 1).getBox()));
if (lessThan(node.getBox(), nodeList.at(counter + 1).getBox()))
{
newNode.setLeft (new SPnode(node));
newNode.setRight(new SPnode((nodeList.at(counter + 1))));
}
else
{
newNode.setRight(new SPnode(node));
newNode.setLeft (new SPnode((nodeList.at(counter + 1))));
}
parentNodeList.push_back(SPnode(newNode));
nodeList.at(counter).setIterated(true);
nodeList.at(counter + 1).setIterated(true);
counter += 1;
}
else
{
parentNodeList.push_back(SPnode(node.getBox()));
nodeList.at(counter + 1).setIterated(true);
counter += 1;
}
}
recListToTree(parentNodeList);
}
Any help is appreciated!
recListToTree does not return a value on all paths, as there is not return at the end of the function (crank up the warning level in the compiler for it to tell you this). This garbage return value is the likely cause of your crashes.
Not related to the crash, but a memory leak problem, is that recConstructor is overly complicated (all those duplicated ifs) and will copy things twice (once via the copy constructor invoked by new, and once later by the recursive call to recConstructor).
Related
I am using Visual Studio 2017 as instructed for this project.
I have received four errors for my program that I have been researching for a couple of days and no matter what I have done, I cannot get these errors to disappear.
I have tried making multiple constructors in BDictionary, I have checked all function names and there are no typos, and I have gone over this code with other people and compared their versions to see why it is getting these errors. I am only worried about getting it to run at this point as I can figure out what functions do not work from there. Any and all help would be appreciated.
bagtestmain.cpp -This file cannot be changed
#include <string>
#include <sstream>
#include "ABag.h"
#include "BDictionary.h"
using namespace std;
const size_t DICTIONARY_SIZE = 20;
void PauseScreen(); //Used to pause screen output
/*
* Tests BDictionary with int and string objects only.
*/
int main(int argc, char** argv) {
cout << "Student Name -- CSIS 215 Programming Assignment 1 -- Bag Dictionary" << endl << endl;
BDictionary<int, string> myIntStrDict(DICTIONARY_SIZE);
//Error C2259 'BDictionary<int,std::string>': cannot instantiate abstract class 27
//Error C2664 'BDictionary<int,std::string>::BDictionary(const BDictionary<int,std::string> &)': cannot convert argument 1 from 'const size_t' to 'const BDictionary<int,std::string> &' 27
BDictionary<string, int> myStrIntDict(DICTIONARY_SIZE);
//Error C2259 'BDictionary<std::string,int>': cannot instantiate abstract class 28
//Error C2664 'BDictionary<std::string,int>::BDictionary(const BDictionary<std::string,int> &)': cannot convert argument 1 from 'const size_t' to 'const BDictionary<std::string,int> &' 28
I included the two errors that are with each line.
ABag.h
#ifndef ABAG_H
#define ABAG_H
#include "book.h"
#include "bagADT.h"
#include <string>
#include <stdlib.h>
template <typename E>
class ABag : public Bag<E> {
private:
int position, capacity;
const int max = 10;
E* data;
public:
// constructors/destructor
ABag()
{
max = defaultSize;
capacity = position = 0;
data = new E[max];
}
~ABag()
{
delete[] data;
}
// Insert a new item into the bag -- return false if fails and true if
// successful
bool addItem(const E& item)
{
if (bagCapacity < 10)
{
position++;
data[position]; //incorrect
capacity++;
return true;
}
else
{
return false;
}
}
// Looks for 'item' in the bag and if found updates 'item' with the
// bag value and returns true. Otherwise 'item' is left unchanged
// and the method returns false.
bool remove(E& item)
{
if (position == -1) // check if bag is full
{
return false;
}
else
{
for (int i = position; i >= 0; i--) // loop through each object top to bottom
{
if (data[i] == item) // if the values are equal, then return the item
{
item = data[i];
position--;
for (int j = i; j <= position; j++)
{
data[j] = data[j + 1]; // shift down the objects on top
}
}
}
return true;
}
}
// Removes the top record from the bag, puts it in returnValue, and
// returns true if the bag is not empty. If the bag is empty the
// function returns false and returnValue remains unchanged.
bool removeTop(E& returnValue)
{
if (inspectTop(returnValue))
{
return false;
}
position--; //return
return true;
}
// Finds the record using returnValue and if the record is found updates
// returnValue based on the contents of the bag and returns true. If the
// record is not found the function returns false. Works just like remove()
// except that the found record is not removed from the bag.
bool find(E& returnValue) const
{
if (position == -1)
{
return false;
}
else
{
for (int i = position; i >= 0; i--) // loops through objects and returns value
{
if (data[i] == returnValue)
{
returnValue = data[i]; // returns the KVpair found
return true;
}
}
}
return false;
}
// Inspect the top of the bag. If the bag is empty return
// false and leave 'item' unchanged; otherwise, return true and update
// 'item' with the contents of the bag.
bool inspectTop(E& item) const
{
if (position == -1)
{
return false;
}
else
{
item = data[position];
return true;
}
}
// empties the bag
void emptyBag()
{
position = -1; // Moves the position down to -1, in a sense removing the elements
}
// use the += operator to add an item to the bag
bool operator+=(const E& addend)
{
return addItem(addend); // No need to rewrite addItem, just call it from here
}
// get the size of the bag
int size() const
{
return position + 1; // returns the actual size
}
// get the capacity of the bag
int bagCapacity() const
{
return capacity;
}
// bag methods: addItem, remove, operator+=, size, etc.
};
#endif /* ABAG_H */
BDictionary.h
#ifndef BDICTIONARY_H
#define BDICTIONARY_H
#include "ABag.h"
#include "dictionaryADT.h"
#include "kvpair.h"
#include "book.h"
#include <string>
using namespace std;
template <typename Key, typename E>
class BDictionary : public Dictionary<int, string>{
public:
// constructors/destructor
BDictionary()
{
max = defaultSize;
capacity = -1;
position = -1;
dictionary = new E[max];
} // Default constructor
BDictionary(const Key& k, const Key& e)
{
max = defaultSize;
capacity = position = 0;
}
~BDictionary()
{
delete[] data.
} // Base destructor
// Reinitialize dictionary
void clear()
{
dictionary->emptyBag(); // Calls ABag's emptyBag
}
// Insert a record
// k: The key for the record being inserted.
// e: The record being inserted.
// Return true if insert is successful and false otherwise
bool insert(const Key& k, const E& e)
{
KVpair<int, string> item(k, e);
if (dictionary->addItem(item))
{
return true;
}
else
{
return false;
}
}
// Looks for a record using the key and if found does the following:
// - updates the E& rtnVal
// - removes the record from the dictionary
// - returns true
// If the record is not found the function returns false.
bool remove(const Key& k, const E& rtnVal)
{
KVpair<int, string> item(k, rtnVal);
if (dictionary->remove(item))
{
return true;
}
else
{
return false;
}
}
// Takes an arbitrary record from the dictionary and does the following:
// - updates the E& returnValue
// - removes the record from the dictionary
// - returns true
// If the dictionary is empty the function returns false.
bool removeAny(E& returnValue)
{
/*Key* k;
k = new Key();
KVpair<Key, E> fill(*k, returnValue);
if (dictionary->removeTop(fill)) // Use of removeTop since we can delete ANY arbitrary element
{
returnValue = fill.value();
delete k;
return true;
}
else
{
delete k;
return false;
}*/
KVpair<int, string> item(0, "");
if (dictionary->removeTop(item))
{
//cout << "REMOVEANY: Removed key " << item.key() << ", which contained the value " << item.value() << endl;
return true;
}
else
{
return false;
}
}
// Looks for a record using the key and if found does the following:
// - updates the E& returnValue
// - returns true
// If the record is not found the function returns false.
bool find(const Key& k, E& returnValue) const
{
KVpair<int, string> item(k, returnValue);
if (dictionary->find(item))
{
//std::cout << "FIND: The value at key " << item.key() << " is " << item.value() << endl;
return true;
}
else
{
return false;
}
}
// Return the number of records in the dictionary.
int size()
{
return dictionary->size(); // calls size function from ABag
}
// methods: clear, insert, remove, removeAny, find, size, etc.
private:
//Pointer to a ABag object. You'll need to instantiate the bag in your constructor:
// dictionary = new ABag<KVpair<Key, E>>(size) or something similar depending on how
// you've implemented your ABag constructor(s).
//This pointer gives you access to the bag which stores your data and provides the
//functions you need to build your dictionary.
ABag<KVpair<int, string>>* dictionary;
int capacity, position;
const size_t max;
};
#endif /* BDICTIONARY_H */
I am required to implement a dynamic array that adjusts, dynamically, in accordance with the number of value (temperatures) that are input into the code. I have written the majority of the code for this to be possible, however I have run into a bug and for the life of me, have been unable to locate the issue.
The program is supposed to output the values of temp_a, make temp_b = temp_a, output the value of temp_b, and then clear the value of temp_a, and finally output the values of temp_b once more.
However, when I compile the program, it outputs that the list is full and cannot add any more values, meaning there is a logic error somewhere in the code.
Please forgive me for the lengthy code, as soon as I can locate the error, the code shall be separated into multiple compilations.
#include <iostream>
using namespace std;
class TemperatureList {
private:
int* temp; // pointer to dynamic array
short current_size; // current number of elements
short max_size; // max number of elements allowed in this list
public:
// Overloading assignment operator
void operator =(const TemperatureList& another_list);
// === Constructors ===
// Default constructor
TemperatureList();
// Constructor that accepts an integer parameter that specifies the max length of the list
TemperatureList(int max);
// Copy constructor that accepts another List as parameter
TemperatureList(const TemperatureList& another_list);
// Destructor
~TemperatureList();
// === Modifier functions ===
// add new_value to end of list if there is still space
void add_temperature(int new_value);
// === Accessor functions ===
// return current current_size of the list
short get_current_size();
// === Other functions ===
// return the last element, or 0 if the list is empty, with a warning output
int get_last();
// return element at the position-th position, or 0 if the list is empty, with a warning output
int get_temp(short position);
// returns if current_size == 0
bool set_temp(short position, int value);
// returns if current_size == 0
bool empty();
// returns if current_size == max_size
bool full();
// Output list separated by commas
friend ostream& operator <<(ostream& outs, const TemperatureList& list);
};
int main() {
TemperatureList temp_a;
temp_a.add_temperature(23.5);
temp_a.add_temperature(24.6);
cout << temp_a;
TemperatureList temp_b = temp_a;
cout << temp_b;
temp_a = TemperatureList();
cout << "Now there's no temperatures in a.\n";
cout << temp_a;
cout << "How about temperatures in b?\n";
cout << temp_b;
return 0;
}
void TemperatureList::operator =(const TemperatureList& another_list) {
delete[] temp;
current_size = another_list.current_size;
max_size = another_list.max_size;
if (current_size > 0) {
temp = new int[max_size];
for (int i = 0; i < max_size; i++) {
temp[i] = another_list.temp[i];
}
}
else {
temp = NULL;
}
}
TemperatureList::TemperatureList() {
current_size = 0;
max_size = 0;
temp = NULL;
}
TemperatureList::TemperatureList(int max) : max_size(max) {
current_size = 0;
temp = new int[max];
}
TemperatureList::TemperatureList(const TemperatureList& another_list) {
current_size = another_list.current_size;
max_size = another_list.max_size;
if (current_size > 0) {
temp = new int[max_size];
for (int i = 0; i < max_size; i++) {
temp[i] = another_list.temp[i];
}
}
else {
temp = NULL;
}
}
TemperatureList::~TemperatureList() {
//cout << "== I am in destructor ==\n";
delete[] temp;
}
void TemperatureList::add_temperature(int new_value) {
if (current_size < max_size) {
temp[current_size] = new_value;
current_size++;
}
else {
cout << "Cannot add value to the list. It is full.\n";
}
}
int TemperatureList::get_last() {
if (empty()) {
cout << "The list is empty\n";
return 0;
}
else {
return temp[current_size - 1];
}
}
int TemperatureList::get_temp(short position) {
if (current_size >= position) {
return temp[position - 1];
}
else {
cout << "There is no temperature\n";
return 0;
}
}
bool TemperatureList::set_temp(short position, int value) {
if (current_size >= position) {
temp[position - 1] = value;
return true;
}
else {
return false;
}
}
short TemperatureList::get_current_size() {
return current_size;
}
bool TemperatureList::empty() {
return (current_size == 0);
}
bool TemperatureList::full() {
return (current_size == max_size);
}
ostream& operator <<(ostream& outs, const TemperatureList& list) {
int i;
for (i = 0; i < (list.current_size - 1); i++) {
outs << list.temp[i] << ",";
}
outs << list.temp[i];
return outs;
}
The logic error seems to stem from the fact that you initialize your current_size and max_size to zero. So, unless your run the overloaded constructor (wherein you’re set the max_size), every call to addTemperature() is going to fail the (current_size < max_size) check because they are both equal to zero.
I am practicing using templates and classes in C++. My goal is to write a template class for a deque. It will have functions to "insert_head", "insert_tail", "remove_tail", and "remove head", along with the ability to be printed using "cout". Also, the '=' operator must be able to be used to copy one instance of the class to another instance. Here is my current code:
#ifndef DEQUE_H
#define DEQUE_H
template <typename T>
class Deque {
public:
Deque(int size = 0, int capacity = 1000) : size_(size), capacity_(capacity)
{}
Deque(Deque & d) : x_(d.x()), size_(d.size()), capacity_(d.capacity()) {}
std::ostream & operator<<(std::ostream & cout) {
cout << '[';
if (size_ > 0) {
for (int i = 0; i < (size_ - 1)* sizeof(T); i += sizeof(T)) {
std::cout << *(x_ + i) << ',';
}
cout << *(x_ + (size_ - 1)* sizeof(T));
}
cout << ']';
return cout;
}
Deque operator=(Deque d) {
Deque dq(d);
return dq;
}
void print_test() {
std::cout << '[';
if (size_ > 0) {
for (int i = 0; i < (size_ - 1)* sizeof(T); i += sizeof(T)) {
std::cout << *(x_ + i) << ',';
}
std::cout << *(x_ + (size_ - 1)* sizeof(T));
}
std::cout << ']';
}
int * x() {
return x_;
}
int size() {
return size_;
}
int capacity() {
return capacity_;
}
bool is_empty() {
return size_ == 0;
}
void insert_tail(T tail) {
if (size_ < capacity_) {
*(x_ + sizeof(T) * size_) = tail;
size_++;
} else {
// throw overflow
}
}
T remove_tail() {
if (size_ > 0) {
T ret = *(x_ + sizeof(T) * (size_ - 1));
std::cout << ret;
size_--;
return ret;
} else {
// throw underflow
}
}
void insert_head(T head) {
if (size_ > 0 && size_ < capacity_) {
for (int i = (size_ - 1) * sizeof(T); i < 0; i -= sizeof(T)) {
*(x_ + i + sizeof(T)) = *(x_ + i);
}
}
if (size_ < capacity_) {
*x_ = head;
size_++;
} else {
// throw overflow
}
}
T remove_head() {
if (size_ > 0) {
T ret = *x_;
for (int i = sizeof(T); i < size_* sizeof(T); i += sizeof(T)) {
*(x_ + i - sizeof(T)) = *(x_ + i);
}
size_--;
return ret;
} else {
// throw underflow
}
}
private:
T * x_;
int size_;
int capacity_;
};
#endif
Here is my test code using that class:
#include <iostream>
#include "Deque.h"
int main(int argc, char const *argv[])
{
Deque< int > dq;
dq.insert_head(1);
// dq.insert_head(2); // adding head when not empty causes bug
dq.insert_tail(3);
dq.insert_tail(4);
dq.insert_tail(5);
dq.print_test(); std::cout << std::endl;
// std::cout << dq; // '<<' not overloaded properly'
std::cout << dq.remove_head() << " head removed\n";
// int x = dq.remove_head(); // seg faults when assigning returned value to a variable
dq.insert_tail(2);
dq.print_test();
std::cout << std::endl;
Deque< int > dq1(dq);
Deque< int > dq2;
// dq2 = dq1; // '=' not overloaded properly
return 0;
}
Each of my four problems is in a commented out line of code in my test file, here is a further explaination:
When "dq.insert_head(2)" is called and dq is not empty (size > 0) I try to shift all the other elements in the deque over one position so I can insert the new value there, there is a problem and the elements are not moved over.
"std::cout << dq" does not print dq like it should. The code is very similar to the "print_test()" method, however when I run the program I get the error "no match for operator <<". Is this because it is template class? Or am I doing something else completely wrong?
When trying to remove the head or tail from the deque, I am trying to return the value removed. In the line of code not commented out, the returned value is printed as it should, but the following line of code causes a seg fault. Is it because I'm trying to assign a template varabale to an integer variable?
My last issue is the '=' operator is not copying one instance of the class to another. My goal was to create a new instance of the class then return that instance (as you can see in the "Deque operator=(Deque d)") but that is not working as I hoped. What is the best way to overload the '=' function using template classes.
Thank you for your help, the answer to any of these questions is much appreciated.
All of your functions have issues:
Deque(int size = 0, int capacity = 1000) : size_(size), capacity_(capacity) {}
If you allows to specify a size, then you would have to allocate and initialize memory for those items. You should only specify capacity.
x_ is not initialized.
Assuming, you want a fixed capacity, then your constructor should be:
Deque(int capacity = 1000)
: size_(0)
, x_(new T[capacity])
, capacity_(capacity)
{
}
And even that is a simplified version as it would call the constructor for all items which might be inefficient and require that T has an accessible default constructor.
And now for the copy constructor:
The copy constructor should do deep copy. Otherwise, your program will (probably) crash after deleting the first Deque for which you have done copies as deleting an item twice is undefined behavior.
The prototype should take a constant reference as in: Deque(const Deque &other);
The code would look similar to this:
Deque(const Deque &other)
: capacity_(other.capacity_)
, x_(new T[other.capacity_])
, size_(other.size_)
{
for (int i = 0; i != size_; ++i)
{
x_[i] = other.x_[i];
}
}
For the <<, the prototype should be:
friend std::ostream & operator<<(std::ostream &cout, const T &data)
assuming it is declared inside the class to access private fields. You need to pass the data on which the operator works.
For the assignment operator, something like this could works:
Deque& operator=(const Deque &other)
{
// Use swap idiom...
Deque tmp(other);
// Swap pointers so old x_ get destroyed...
T *old_x = x_;
x_ = tmp.x_;
tmp.x_ = old_x;
// Usually one would use std::swap.
// Here as tmp get destroyed, it is not strictly to swap capacity_ and size_.
capacity_ = tmp.capacity_;
size_ = tmp.size_;
}
Now for the x() function:
- If you do a queue, you probably don't want to expose data so the function should be removed.
- If it was kept, the function should be const and returns a pointer to T: T *x() const; for the expected functionality.
size, capacity and is_empty should all be const member functions.
insert_tail and remove_tail problems have been explain in other people comments (in particular extraneous sizeof).
Similar problems for insert_head and remove_head also. In addition, the code that copy existing items could be refactored inside a private function to follows the DRY principle and avoid code duplication.
The answer to your first problem is to remove the sizeof(T) so you end up with this
for (int i = (size_ - 1); i > 0; i --) {
*(x_ + i + 1) = *(x_ + i);
}
The answer to your second problem is to change your declaration for your << overload to friend std::ostream & operator<<(std::ostream & x, Deque n) and initialize the body outside the class.
The answer to the third problem is that you can't return an int pointer which may point to a different block of memory location that what T could be.
The answer to the fourth question is to do the following:
Deque& operator=(const Deque& d) {
x_ = d.x_; // Deep copy
size_ = d.size_;
capacity_ = d.capacity_;
return *this;
}
I want to understand what iterators are, how they are made. So int this code iterators are created for Stack.My question are
how we can write Stack s2(s1), if we don't have class named Stack which has explicit constructor, insted we have StackIter class , which has explicit constructor ?
What does this mean: StackIter *Stack::createIterator()const,we have class StackIter, then pointer on stack, I don't understand at all. Maybe when we write Stack s2(s1), it comes from here ?
So the meaning of iterator is shown in bool operator == (const Stack &l, const Stack &r) ?
Thanks a lot in advance .
Any response will be appreciated
#include <iostream>
using namespace std;
class Stack
{
int items[10];
int sp;
public:
friend class StackIter;
Stack()
{
sp = - 1;
}
void push(int in)
{
items[++sp] = in;
}
int pop()
{
return items[sp--];
}
bool isEmpty()
{
return (sp == - 1);
}
StackIter *createIterator()const; // 2. Add a createIterator() member
};
class StackIter
{
// 1. Design an "iterator" class
const Stack *stk;
int index;
public:
StackIter(const Stack *s)
{
stk = s;
}
void first()
{
index = 0;
}
void next()
{
index++;
}
bool isDone()
{
return index == stk->sp + 1;
}
int currentItem()
{
return stk->items[index];
}
};
StackIter *Stack::createIterator()const
{
return new StackIter(this);
}
bool operator == (const Stack &l, const Stack &r)
{
// 3. Clients ask the container object to create an iterator object
StackIter *itl = l.createIterator();
StackIter *itr = r.createIterator();
// 4. Clients use the first(), isDone(), next(), and currentItem() protocol
for (itl->first(), itr->first(); !itl->isDone(); itl->next(), itr->next())
if (itl->currentItem() != itr->currentItem())
break;
bool ans = itl->isDone() && itr->isDone();
delete itl;
delete itr;
return ans;
}
int main()
{
Stack s1;
for (int i = 1; i < 5; i++)
s1.push(i);
Stack s2(s1), s3(s1), s4(s1), s5(s1);
s3.pop();
s5.pop();
s4.push(2);
s5.push(9);
cout << "1 == 2 is " << (s1 == s2) << endl;
cout << "1 == 3 is " << (s1 == s3) << endl;
cout << "1 == 4 is " << (s1 == s4) << endl;
cout << "1 == 5 is " << (s1 == s5) << endl;
}
1) Default copy constructor operator:
Stack s2(s1) correcsponds to the Stack s2(const Stack& x) copy constructor, generated by your compiler if you don't tell him to use another one.
2) Definition of a member function
StackIter *Stack::createIterator()const { ...} is the definition of the member function createIterator() that is declared in you class but was not yet defined. Basically it returns a pointer to a StackIter.
3) definition of an operator
Not sure about your question.
bool operator == (const Stack &l, const Stack &r) defines the comparison between two stacks. So a priori not directly related to iterators.
But indeed, this function demonstrates the use of the iterators.
P.S: I think you are working on an example of this tutorial. I'd however warmly recommend you to read "The C++ Programming Language" or some similar books who give you full insight on working with iterator and address all the prerequisites.
TL;DR
I have a vector of std::shared_ptr's that I have to run std::push_heap, std::pop_heap, and std::find on. How do I compare the the things the pointers are pointing to rather than the pointers themselves?
Hi, I am trying to implement A* in my game and am having some trouble figuring out how to store all the nodes. Since I can't store a member of the same class in a class I have to use pointers. I can't use raw pointers because I realized that I would end up pointing to locations in a std::vector rather than the values stored in them. I now have decided that I will use std::shared_ptr's. However, I come across the issue in the TL;DR above. The Node object has an overload of the > operator, how can I end up using that. Here is my code; if anyone sees something that can be improved, please do say so.
Node.h
#ifndef NODE_H
#define NODE_H
#include <memory>
#include <SFML/Graphics.hpp>
class Node
{
public:
//Constructors
Node(std::shared_ptr<Node>, const sf::Vector2i&);
Node(const sf::Vector2i&);
//Getters
std::shared_ptr<Node> getParentNodePtr() const;
float getDistanceValue() const;
float getHeuristicValue() const;
float getTotalValue() const;
bool isStartNode() const;
sf::Vector2i getPosition() const;
//Setters
void setDistanceValue(float);
void setHeuristicValue(float);
void setTotalValue(float);
void setIsStartNode(bool);
//Comparison overloads
bool operator() (const Node&, const Node&) const;
bool operator== (const Node&) const;
bool operator< (const Node&) const;
private:
std::shared_ptr<Node> parentNodePtr_;
//Values
sf::Vector2i position_;
float distanceValue_ = 0.0f;
float heuristicValue_ = 0.0f;
float totalValue_ = 0.0f;
bool startNode_ = false;
};
#endif
Node.cpp
#include "Node.h"
Node::Node(std::shared_ptr<Node> parentNodePtr, const sf::Vector2i& position)
:parentNodePtr_(parentNodePtr)
{
position_ = parentNodePtr_->getPosition() + position * 32;
}
Node::Node(const sf::Vector2i& position)
:position_(position)
{}
//Getters
std::shared_ptr<Node> Node::getParentNodePtr() const { return parentNodePtr_; }
float Node::getDistanceValue() const { return distanceValue_; }
float Node::getHeuristicValue() const { return heuristicValue_; }
float Node::getTotalValue() const { return totalValue_; }
bool Node::isStartNode() const { return startNode_; }
sf::Vector2i Node::getPosition() const { return position_; }
//Setters
void Node::setDistanceValue(float distanceValue) { distanceValue_ = distanceValue; }
void Node::setHeuristicValue(float heuristicValue) { heuristicValue_ = heuristicValue; }
void Node::setTotalValue(float totalValue) { totalValue_ = totalValue; }
void Node::setIsStartNode(bool startNode) { startNode_ = startNode; }
//Comparison functor
bool Node::operator() (const Node& lhv, const Node& rhv) const {return lhv.totalValue_ < rhv.totalValue_; /*Backwards because I want a min-heap/min-priority-queue*/ }
bool Node::operator== (const Node& rhv) const {return position_ == rhv.position_; }
bool Node::operator< (const Node& rhv) const { return totalValue_ > rhv.totalValue_; }
Relevant Zombie.cpp
NOTE: sPNodes_ is a std::stack of std::shared_ptr's
Formatting wrong, use pastebin: http://pastebin.com/Z9NxTELV
void Zombie::findPath(std::vector< std::vector<Tile> >* pVTiles)
{
if(targetPosition_ != sf::Vector2i(0.0f, 0.0f))
{
//Initiates lists
std::vector<std::shared_ptr<Node>> openList;
std::vector<std::shared_ptr<Node>> closedList;
std::shared_ptr<Node> currentNode;
bool pathFound = false;
//Initiates the great journey
openList.push_back(std::make_shared<Node>(sf::Vector2i(positionGlobal_.x - fmod(positionGlobal_.x, 32.0f) + 16.0f, positionGlobal_.y - fmod(positionGlobal_.y, 32.0f) + 16.0f)));
openList.back()->setIsStartNode(true);
std::push_heap(openList.begin(), openList.end()); //NEED COMPARISON FOR THE POINTERS HERE
while(!pathFound)
{
//Gets the a pointer to the top item in the openList, then moves it to the closed list
std::pop_heap(openList.begin(), openList.end()); //NEED COMPARISON FOR THE POINTERS HERE
currentNode = openList.back();
closedList.push_back(currentNode);
openList.pop_back();
//Debug info
std::cout << std::endl << "TargetPosition: " << targetPosition_.x / 32 << ", " << targetPosition_.y / 32 << std::endl;
std::cout << "Position: " << currentNode->getPosition().x / 32 << ", " << currentNode->getPosition().y / 32 << std::endl;
std::cout << "Distance from start node: " << currentNode->getDistanceValue() / 32.0f << std::endl;
std::cout << "Heuristic Value: " << currentNode->getHeuristicValue() / 32.0f<< std::endl;
std::cout << "Total: " << currentNode->getTotalValue() / 32.0f << std::endl;
//For the eight neighboring tiles/nodes
for (int i = 0; i < 8; ++i)
{
int xPos;
int yPos;
//xPos
if(i == 0 || i == 4)
xPos = 0;
else if(i > 0 && i < 4)
xPos = 1;
else
xPos = -1;
//yPos
if(i == 2 || i == 6)
yPos = 0;
else if(i < 2 || i > 6)
yPos = 1;
else
yPos = -1;
sf::Vector2i nodePosition = currentNode->getPosition() + sf::Vector2i(xPos * 32, yPos * 32);
//Stop working if the node/tile is a wall or contains a tree
if(pVTiles->at(nodePosition.x / 32).at(nodePosition.y / 32).getType() == "unwalkable" || pVTiles->at(nodePosition.y / 32).at(nodePosition.x / 32).hasItem())
continue;
//Creates a node for the tile
auto node = std::make_shared<Node>(currentNode, sf::Vector2i(xPos, yPos));
//Checks to see if it is the target adds node to stack and breaks if so
if(node->getPosition() == targetPosition_)
{
std::cout << "found target!" << std::endl;
pathFound = true;
sPNodes_.push(node);
break;
}
//If it's not the target
if(!pathFound)
{
float parentDistanceValue = node->getParentNodePtr()->getDistanceValue();
//Distance is 1.4f x 32 if diagonal, 1 x 32 otherwise
if(xPos == yPos)
node->setDistanceValue(parentDistanceValue + 44.8f);
else
node->setDistanceValue(parentDistanceValue + 32.0f);
//Gets the distance to the target(Heuristic) and then gets the total(Distance + Heuristic)
node->setHeuristicValue(sqrt(pow(node->getPosition().x - targetPosition_.x, 2) + pow(node->getPosition().y - targetPosition_.y, 2)));
node->setTotalValue(node->getHeuristicValue() + node->getDistanceValue());
//Makes sure the node is not already in the open or closed list (NEED TO COMPARE VALUE OF WHAT THE POINTERS POINT TO HERE)
if(std::find(openList.begin(), openList.end(), node) == openList.end() && std::find(closedList.begin(), closedList.end(), node) == closedList.end())
{
openList.push_back(node);
std::push_heap(openList.begin(), openList.end()); //NEED COMPARISON HERE
}
}
}
}
//Keeps stacking parent nodes until the start is reached
while(!sPNodes_.top()->isStartNode())
{
std::cout << "stacking backward..." << std::endl;
std::cout << "Position: " << sPNodes_.top()->getPosition().x / 32 << ", " << sPNodes_.top()->getPosition().y / 32 << std::endl;
auto parent = sPNodes_.top()->getParentNodePtr();
sPNodes_.push(parent);
}
}
}
Thanks!
The second form of std::push_heap takes custom comparator as the third parameter, so you can give it the < overload:
struct SPtrNodeLess {
bool operator()(const std::shared_ptr<Node> &first, const std::shared_ptr<Node> &second) const {
return *first < *second;
}
}
std::push_heap(h.begin(), h.end(), SPtrNodeLess())
The std::find_if takes the unary predicate in similar fashion:
struct NodeSPtrEqual {
const Node &n;
NodeSPtrEqual(const Node &n) : n(n) {}
bool operator()(const std::shared_ptr<Node> &n2) {
return n == *n2;
}
}
std::find_if(h.begin(), h.end(), NodeSPtrEqual(node));
Or alternatively you can overload the operator== and use classic std::find:
bool operator==(const Node &n, const std::shared_ptr<Node> &n2) {
return n == *n2;
}
bool operator==(const std::shared_ptr<Node> &n, const Node &n2) {
return *n == n2;
}
std::find(h.begin(), h.end(), node);