setting const strings equal in method c++? - c++

I'm having trouble with the removeItem method because an error occurs right after it's called.
In this method I'm trying to set the array member with the sku in the argument to nullptr and "remove" it.
I think it has something to do with the equalization: if(sku == shoppingList[i]->getSKU()). Or maybe something to do with const. The array has pointers to objects of type Product.
This belongs to CustomerOrder.cpp
CustomerOrder::CustomerOrder()
: shoppingList()
{
}
void CustomerOrder::removeItem(const string &sku)
{
for(int i =0; i< 20; i++)
{
if(sku == shoppingList[i]->getSKU())
{
shoppingList[i] = nullptr;
}
}
}
This belongs in Product.h
private:
std::string sku;
this belongs to Product.cpp
const string & Product::getSKU() const
{
return sku;
}

Change the method the following way
void CustomerOrder::removeItem( const string &sku )
{
for( int i = 0; i < shoppingList.size(); i++ )
{
if( shoppingList[i] && sku == shoppingList[i]->getSKU() )
{
delete shoppingList[i];
shoppingList[i] = nullptr;
}
}
}
I think that the problem is that you tried to call a method for a pointer to Product that was already set to nullptr

My best guess is that your code isn't written to handle nullptr entries in your array. Since you don't actually show where the error occurs or the type of shopping list, it's hard to say exactly what's going wrong. Setting a std::string* to nullptr won't remove it from an array of type std::string*. If you are interested in easy removal of items, consider a different data structure.

Related

Returning a new object from a object returning function c++

I'm working on a program that intersects according to set theory two sets represented by 2 objects. Each objects can contain 0 or more elements.
The function is given and cannot be changed only the implementation inside.
In my code, I check the invoking object and the second object (otherIntSet) are empty, if yes, they intersect at the empty set.
If they contain any elements I check to see if the element in data[] is contained in the otherIntSet. I use "return IntSet();" but all i get is empty set.
IntSet IntSet::intersect(const IntSet& otherIntSet) const
{
if ( (this->isEmpty() ) && (otherIntSet.isEmpty() ) )
{
return IntSet();
}
else
{
for (int i = 0; i < used; ++i)
{
if (otherIntSet.contains(data[i]) )
{
IntSet().add(data[i]);
cout << IntSet();
}
}
}
}
I'm not sure how to return the new object created properly so that the elements that are added to it are actually saved.
Thank you
In this loop:
for (int i = 0; i < used; ++i)
{
if (otherIntSet.contains(data[i]) )
{
IntSet().add(data[i]);
cout << IntSet();
}
}
you create a temporary IntSet object in each iteration, which then what? Disappears? So what's the point? What you want instead is to have one object, fill it up and return:
IntSet result;
for (int i = 0; i < used; ++i)
{
if (otherIntSet.contains(data[i]) )
{
result.add(data[i]);
}
}
return result;
BTW your first condition should probably be "or", it's a better (wider) check than "and":
if ( (this->isEmpty() ) || (otherIntSet.isEmpty() ) )
You can play around and even end up with something like this:
IntSet IntSet::intersect(const IntSet& otherIntSet) const
{
IntSet result;
if (!otherIntSet.isEmpty()) // <-- note negation
{
// We don't need to check if this->isEmpty(), the loop
// won't loop anyway if it is. And in case it isn't
// it saves us unnecessary call. Assuming that "isEmpty()"
// is derived from "used".
for (int i = 0; i < used; ++i)
{
if (otherIntSet.contains(data[i]) )
{
result.add(data[i]);
}
}
}
return result;
}

Segmentation fault due to size() function of self-implemented data structure in C++

I am using a vector of vector in my A3 code. I sort the vector of vector's at insertion. I store my keys in the 0th index of each sub vector.
In my size method, I am trying to use the direct call for checking the size. The code below outlines my attempt. However, I get a segmentation fault on execution. Can anyone help me understand the reason for the same?
vector<vector<int>> pairs; //sorted in the insert method
int size(int key) const {
if( pairs[key].size() == 0 ) { return -1; }
else { return pairs[key].size() - 1; }
}
I have implemented the same successfully previously, however, it was a very inefficient solution using linear search. Here is the code for the same:
int size(int key) const
{
for( int i=0; i<pairs.size(); i++)
{
if( pairs[i][0] == key )
{
return pairs[i].size() - 1;
}
}
return -1;
}
This code is not enough to tell you what is happening, we can only make a guess.
I would say that your leak comes from the method data: you create a copy of the data and then return a pointer to this copy. It would be better to return an unique_ptr, so the memory is released automatically.
If you cannot change the definition of the method, then you could change the body of the method by this one:
int length = size(key);
if( length == -1 )
return nullptr;
for( int i=0; i<pairs.size(); i++)
{
if( pairs[i][0] == key )
{
return &pairs[i][1];
}
}
return nullptr;

Need to reference and update value from nested class C++

Bear with me, I'm new to C++. I'm trying to update a value which is stored in a vector, but I'm getting this error:
non-const lvalue reference to type 'Node'
I'm using a simple wrapper around std::vector so I can share methods like contains and others (similar to how the ArrayList is in Java).
#include <vector>
using namespace std;
template <class T> class NewFrames {
public:
// truncated ...
bool contains(T data) {
for(int i = 0; i < this->vec->size(); i++) {
if(this->vec->at(i) == data) {
return true;
}
}
return false;
}
int indexOf(T data) {
for(int i = 0; i < this->vec->size(); i++) {
if(this->vec->at(i) == data) {
return i;
}
}
return -1;
}
T get(int index) {
if(index > this->vec->size()) {
throw std::out_of_range("Cannot get index that exceeds the capacity");
}
return this->vec->at(index);
}
private:
vector<T> *vec;
};
#endif // A2_NEWFRAMES_H
The class which utilizes this wrapper is defined as follows:
#include "Page.h"
#include "NewFrames.h"
class Algo {
private:
typedef struct Node {
unsigned reference:1;
int data;
unsigned long _time;
Node() { }
Node(int data) {
this->data = data;
this->reference = 0;
this->_time = (unsigned long) time(NULL);
}
} Node;
unsigned _faults;
Page page;
NewFrames<Node> *frames;
};
I'm at a point where I need to reference one of the Node objects inside of the vector, but I need to be able to change reference to a different value. From what I've found on SO, I need to do this:
const Node &n = this->frames->get(this->frames->indexOf(data));
I've tried just using:
Node n = this->frames->get(this->frames->indexOf(data));
n.reference = 1;
and then viewing the data in the debugger, but the value is not updated when I check later on. Consider this:
const int data = this->page.pages[i];
const bool contains = this->frames->contains(Node(data));
Node node = this->frames->get(index);
for(unsigned i = 0; i < this->page.pages.size(); i++) {
if(node == NULL && !contains) {
// add node
} else if(contains) {
Node n = this->frames->get(this->frames->indexOf(data));
if(n.reference == 0) {
n.reference = 1;
} else {
n.reference = 0;
}
} else {
// do other stuff
}
}
With subsequent passes of the loop, the node with that particular data value is somehow different.
But if I attempt to change n.reference, I'll get an error because const is preventing the object from changing. Is there a way I can get this node so I can change it? I'm coming from the friendly Java world where something like this would work, but I want to know/understand why this doesn't work in C++.
Node n = this->frames->get(this->frames->indexOf(data));
n.reference = 1;
This copies the Node from frames and stores the copy as the object n. Modifying the copy does not change the original node.
The simplest "fix" is to use a reference. That means changing the return type of get from T to T&, and changing the previous two lines to
Node& n = this->frames->get(this->frames->indexOf(data));
n.reference = 1;
That should get the code to work. But there is so much indirection in the code that there are likely to be other problems that haven't shown up yet. As #nwp said in a comment, using vector<T> instead of vector<T>* will save you many headaches.
And while I'm giving style advice, get rid of those this->s; they're just noise. And simplify the belt-and-suspenders validity checks: when you loop from 0 to vec.size() you don't need to check that the index is okay when you access the element; change vec.at(i) to vec[i]. And in get, note that vec.at(index) will throw an exception if index is out of bounds, so you can either skip the initial range check or keep the check (after fixing it so that it checks the actual range) and, again, use vec[index] instead of vec.at(index).

Template array of pointers to objects of child classes as argument for a function

I have a few classes that inherit the same class with a print method. I also have a custom-made dynamic array template class. I have created a few dynamic arrays of pointers to objects from the child classes. For every array I want to have a separate function for calling all the print methods of the objects pointed by the pointers- some times I want to print only the "weapons", sometimes only the "modifications" or sometimes everything. So far I have tried two solutions- copy-pasting the first method (as shown in the code) for every array or converting the dynamic arrays into arrays of pointers to the "mother" class and passing the new ones as an argument to an universal print function.
And here is some code:
class Item {...}
class Modification : public Item {...}
class Equipment : public Item {...}
DynamicArray<Modification*> modification;
DynamicArray<Equipment*> weapon;
//The first way:
void printModsInfo ()
{
if (modification.size() == 0)
cout<<"No mods in inventory\n";
else
for (int i = 0; i < modification.size(); i++)
modification.returnElement(i)->printInfo();
}
void printWeaponsInfo ()
{
if (weapon.size() == 0)
cout<<"No weapons in inventory\n";
else
for (int i = 0; i < weapon.size(); i++)
weapon.returnElement(i)->printInfo();
}
//The second way:
void _printModsInfo ()
{
Item** tempRef = new Item*[modification.size()];//array of pointers
for (int i = 0; i < modification.size(); i++)//converting DynamicArray<Modification*> into Item** tempRef
tempRef[i] = modification.returnElement(i);
printCertainStuffInInventory (tempRef, modification.size());
delete tempRef;
}
void _printWeaponsInfo ()
{
Item** tempRef = new Item*[weapon.size()];
for (int i = 0; i < weapon.size(); i++)
tempRef[i] = weapon.returnElement(i);
printCertainStuffInInventory (tempRef, weapon.size());
delete tempRef;
}
void printCertainStuff (Item** arr, int size)
{
if (size == 0)
cout<<"Nothing from this type in inventory...\n";
else
for (int i = 0; i < size; i++)
arr[i]->printInfo();
}
So I have two choices: copy-paste the five rows from the fist way, or copy-paste the more complicated five rows from the second way and add five more rows for the printing function. But what I really want to do is to simply pass the dynamic arrays as arguments and make the conversion (if needed) in the printing function- or to simply call the "printer" by writing: printCertainStuff(modification); (or "weapon" or whatever). And this is required by the design of the whole project. I did consult my teacher, but the answer was that there is no way to do that without converting before calling the function.
But still- is there a way to pass such dynamic arrays as arguments the way I want?
I'm not 100% clear on what you're wanting, but if it is to combine all your print methods you could try using a template:
template< class T >
void printInfo ( const T& arr, const char* failmessage )
{
if (arr.size() == 0)
cout<<failmessage;
else
for (int i = 0; i < arr.size(); i++)
arr.returnElement(i)->printInfo();
}
And then to use for weapons you'd go:
printInfo( weapon, "No weapons in inventory\n" );
And similarly for modifications.

Set pointer to element in vector to null, then check whether pointer is null (C++)

I would like to set pointers to some elements in my vector array to NULL (based on a criteria), and then check whether an element pointer is NULL. If the pointer pointing that element is NULL, I remove the element from my vector array.
My compiler is giving me an error, saying that the address expression must be an lvalue or function designator and I do not understand why (line location commented in code). Since I am taking the address of the value using &, am I not seeing if the pointer pointing to that element is NULL?
I included the preceding code as the error may lie there,
Relevant code:
vector<particle> pl = c.particlelist;
vector<particle> noncollision = c.particlelist;
vector<vector<particle>> collisionlist = new vector<vector<particle>>();
for (int i = 0; i < c.numparticles-1; i++){
particle first = pl[i];
for (int j = i+1; j < c.numparticles; j++)
{
particle second = pl[j];
double d = distance(first, second);
if (d==0)
{
vector<particle> temp = {pl[i], pl[j]};
collisionlist.push_back(temp);
noncollision[i].setxposint(NULL);
noncollision[j].setxposint(NULL);
}
else
{
}
}
}
int j = 0;
for (int i = 0; i < noncollision.size(); i++)
{
if (&(noncollision[i].getxpos()) == NULL) ////// ERROR HERE
{
noncollision.erase(noncollision.begin()+i);
}
else
{
j++;
}
}
I am new to C++, and if you could suggest a more elegant way to do this, or a fix, it would be much appreciated. I also assume that my method of setting the pointer to an element, noncollision[i].setxposint(NULL); is correct? Can I return an integer using a function, and take the address?
Functions for getxpos and setxposint:
int particle::getxpos(){
return xpos;
}
void particle::setxposint(int b){
xpos = b;
}
You're using & to take a pointer to a temporary vale (the return from getxpos) which isn't allowed; since a temporary will be going away, the address won't be useful in any way so the language doesn't allow it. It certainly wouldn't ever be NULL even if you could get its address.
noncollision[i].setxposint(NULL);
All that line is doing is setting xpos to zero. Generally the term NULL is used with pointers, and 0 is used with things like integers. NULL is usually a macro for 0L anyway.
&(noncollision[i].getxpos()) == NULL
What this is doing, which is incorrect, is attempting to take the address of the return value from the member method getxpos() and compare it to NULL. Whereas what you really want to do is simply see if the function returns zero. So simply change this line to:
noncollision[i].getxpos() == 0
I'll explain why the compiler doesn't understand what you mean.
When you write
&(someFunction())
you are asking for the address of the thing that the function returns. But functions return values. A value doesn't have an address. Variables have addresses.
When something is a word of memory (which will contain a value), it can be used as an lvalue (left-value), because you can put things into that word of memory:
int b = 1; //make room for an `int` on the stack, then put a `1` there.
When something is just a value, it can only ever be used as an rvalue. The following would not compile, for the same reason that your code would not:
int b; //make room for an `int` on the stack.
42 = b; //ERROR, this makes no sense.
if (42 == NULL) { std::cout << "this is never true" << std::endl; }
&42; //ERROR, 42 isn't a piece of memory, it's a value.
(Caveat: you can use values to refer to words in memory: this usage is called a pointer, e.g.
int b = 1;
*((int *)(42)) = b;
meaning "put the value of b into the memory which has the address 42. This compiles fine (but crashes if you're not allowed to write to the memory at 42.)
It looks to me you're trying to keep track of 'visited' items, not sure exactly in which way.
Instead of "modifying" the items, you could use an "external" mark. A set looks to be fine here. You could use a set of iterators into the particle list, or in this case a set of indices (i,j) which will likely be more stable.
Here's a start:
#include <vector>
#include <set>
struct particle { };
double distance(particle const&, particle const&) { return 1.0; }
struct context
{
std::size_t numparticles;
std::vector<particle> particlelist;
context() : numparticles(100), particlelist(numparticles) {}
};
static context c;
int main()
{
using std::vector;
using std::size_t;
vector<particle> pl = c.particlelist;
vector<vector<particle>> collisionlist;
std::set<size_t> collision;
for(size_t i = 0; i < c.numparticles-1; i++)
{
particle first = pl[i];
for(size_t j = i+1; j < c.numparticles; j++)
{
particle second = pl[j];
double d = distance(first, second);
if(d < 0.0001)
{
collisionlist.push_back({pl[i], pl[j]});
collision.insert(i);
collision.insert(j);
}
else
{
}
}
}
for(size_t i = 0; i < pl.size(); i++)
{
if(collision.end() != collision.find(i))
{
// do something
}
}
// alternatively
for (int index : collision)
{
particle& p = pl[index];
// do something
}
}
NOTE Be very very wary of floating point comparison like
if (d==0.0) // uhoh
because it will likely not do what you expect
How dangerous is it to compare floating point values?
What is the most effective way for float and double comparison?
Is floating-point == ever OK?
It seems that you are trying to check pairs of points for collisions. You then record for each point whether it has any collision. This is best handled by a simple list of flags:
std::vector<bool> has_collision(c.numparticles, false); // init: no collisions found
Afterwards:
if (d==0)
{
has_collision[i] = true;
has_collision[j] = true;
}
At the end, iterate over the list of flags and get the points that have no collisions:
for (size_t i = 0; i < c.numparticles; ++i)
{
if (!has_collision[i])
{
// whatever
// possibly push_back pl[i] into some list
}
}
In addition: using a vector to hold a pair (i,j) of points is confusing. Standard library has the std::pair type for purposes such as this.
Also: you don't need explicit dynamic allocation (new); let Standard Library manage memory for you in a safe, non-confusing way. Instead of
vector<vector<particle>> collisionlist = *new vector<vector<particle>>();
Use
vector<vector<particle>> collisionlist;
(or vector<pair<particle, particle>>, as described above).