Segmentation fault due to size() function of self-implemented data structure in C++ - 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;

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;
}

std::unordered_map how to free struct created with malloc. Are 2 queries into the map required?

The following block of code seems to run fine
Generates:
Add 1000 things
_MyMap now holds [1000] things
_MyMap free'd and erased. size now [0]
#include <unordered_map>
#include <iostream>
typedef struct _entry
{
int now;
} ENTRY, * PENTRY;
std::unordered_map<int, PENTRY> _MyMap;
typedef std::unordered_map<int, PENTRY>::iterator itEntry;
int Now()
{
return 10;
}
main function, adding comments because the site won't let me just add code
int main()
{
PENTRY pE = NULL;
std::pair<itEntry, bool> r;
printf("Add 1000 things\n");
for (int i = 0; i < 1000; i++)
{
pE = (PENTRY)malloc(sizeof(ENTRY));
pE->now = Now();
r = _MyMap.insert(std::make_pair(i, pE));
if (false == r.second)
{
printf("For some crazy reason its already there\n");
continue;
}
}
// OK, theres probably 1000 things in there now
printf("_MyMap now holds [%u] things\n", _MyMap.size() );
// The following seems stupid, but I don't understand how to free the memory otherwise
for (int i = 0; i < 1000; i++)
{
// first query
auto it = _MyMap.find(i);
// if malloc failed on an attempt earlier this could be NULL right?
// I've had free impls crash when given NULL, so I check.
if (it != _MyMap.end() &&
NULL != it->second)
free(it->second);
// second query
_MyMap.erase(i);
}
printf("_MyMap free'd and erased. size now [%u]\n", _MyMap.size());
return 0;
}
Questions are inline in the comments
You probably want this:
auto it = _Map.find(idUser);
if (it != _Map.end())
{
free(it->second);
_Map.erase (it);
}
But it's really not a good idea to store a raw pointer in a collection this way. You should, ideally, just store the data directly in the map rather than storing a pointer to it. Otherwise, use std::unique_ptr so that the destruction of the pointer automatically frees the data.

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).

How to reset a static vector inside a function?

I am trying to solve a certain problem on an online judge using the Dynamic Programming paradigm. I have written a function which memoizes the results of smaller subproblems. But this function will be called t times in a single run. So when the function calls itself I want its "Memory" to be preserved, but when it is called from the driver I wan't the vector to be reset. How do I do that? I think having a global vector and reseting it after each call from the driver is possible, but as I have learnt from books and stack overflow that is "bad programming style". So what is a good sollution to this problem? Heres the code :
class mem{
public:
bool mike_win;
bool written;
};
bool calc(int a){
static vector<mem> memory(a);
if( a == 1){
return false;
}
if(memory[a-1].written == true){
return (!(memory[a-1].mike_win))
}
vector<int> div_list = divis(a);
//^^ divis is a function which takes a number and returns
//all its divisors in descending order in a vector<int>
for(vector<int>::iterator i = div_list.begin();i != div_list.end();i++){
if ( ! ( calc( a / (*i) ))){
memory[a-1].written = true;
memory[a-1].mike_win = true;
return true;
}
}
if(calc(a-1 ) == false){
memory[a-1].written = true;
memory[a-1].mike_win = true;
return true;
}
else{
memory[a-1].written = false;
memory[a-1].mike_win = false;
return false;
}
}
Heres a link to the question. And heres the function divis :
vector<int> divis(int a){
vector<int> div_list(int a )
if(a==2){
return div_list;
}
int k = sqrt(a);
for(int i=2;i<=k;i++){
if(!(a%i)){
div_list.push_back(i);
div_list.push_back(a/i);
}
}
sort(div_list.rbegin(),div_list.rend());
div_list.erase(unique(div_list.begin(),div_list.end()),div_list.end());
return div_list;
}
I think the way I would do it is to create two overloads of calc: on that takes just int as a parameter, and another that takes an int and a reference to vector<int>. That way, a user will call the first overload, which will create the temporary vector for memorization, and pass it to the second function, which passes the reference upon recursion. Kinda like this:
bool calc(int a, vector<int>& memory)
{
// Do your stuff here
// Instead of calling it as calc( a / (*i) ), just call
// it as calc( a / (*i) , memory )
}
bool calc(int a)
{
vector<int> memory(a);
calc(a, memory);
}
That way, you avoid having to do any sort of book-keeping in the heart of your algorithm to determine whether to clear the vector or not; it will be done automatically after the first call returns.

setting const strings equal in method 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.