I created a custom class and custom hash functions for an unordered_set. Each time I try to insert into that unordered_set, I get a memory error:
malloc: *** error for object 0x9000000000000000: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6
It is imperative that I use an unordered_set.
This is my custom class:
template <class T>
class Seed {
private:
Point start;
int seed_size;
T** data;
Seed* seed_match;
T _value;
public:
Seed(int x, int y, int s): seed_size(s), data( new T*[s] ), _value( T() ) {
start = Point(x, y);
for ( int i = 0; i < seed_size; i++ )
data[i] = new T[seed_size];
for ( int i = 0; i < seed_size; i++ ) {
for ( int j = 0; j < seed_size; j++ ) data[i][j] = NULL;
}
seed_match = NULL;
}
~Seed() {
for ( int x = 0; x < seed_size; x++ ) {
delete [] data[x];
}
delete [] data;
}
void add(int x, int y, T color_val) {
assert( data[x][y] == NULL );
data[x][y] = color_val;
_value += color_val;
}
bool match ( const Seed &_match ) {
if ( seed_match == NULL ) {
seed_match = &_match;
return true;
}
else return false;
}
T get_color(int x, int y) const {
assert( x >= 0 );
assert( y >= 0 );
assert( x < seed_size );
assert( y < seed_size );
return data[x][y];
}
bool operator==( const Seed<T> &b ) {
for ( int x = 0; x < seed_size; x++ ) {
for ( int y = 0; y < seed_size; y++ ) {
if ( get_color(x, y) != b.get_color(x, y) ) return false;
}
}
return true;
}
int seed_value() const { return _value; }
};
These are my custom hash functions:
template <class T>
struct SeedEqualByValue {
public:
bool operator()(const Seed<T> & seed1, const Seed<T> & seed2) const {
if (seed1.seed_value() == seed2.seed_value())
return true;
else
return false;
}
};
template <class T>
struct SeedHashByValue {
public:
size_t operator()(const Seed<T> & s1) const {
return std::hash<int>()( s1.seed_value() );
}
};
In my main, I instantiate 3 instances of the Seed class into 3 variables and also instantiate an unordered_set that takes in Seed, with the hash function as my SeedHashByValue struct and my compare function as SeedEqualByValue struct.
After creating the unordered_map, anytime I insert a Seed object into the unordered_map, I get an malloc error and I am not sure how to fix this.
These are the contents of my main function:
Seed<int> b(0, 0, 5);
Seed<int> a(0, 0, 5);
Seed<int> c(0, 0, 5);
c.add(4, 4, 100);
a.add(1, 2, 4);
a.add(1, 1, 3);
b.add(1, 1, 3);
unordered_set<Seed<int>, SeedHashByValue<int>, SeedEqualByValue<int> > seeds;
seeds.insert(c);
Also, Point is just a class that holds x and y values with public member variables int x and int y, in case anyone needed clarification.
To follow-up on what #Algirdas said, I believe what's happening is that the Seed is shallow-copied into the set, so you end up with a double delete on the same parent pointer, once when the set goes out of scope, and once when the variable goes out of scope.
You'll need to modify how you are handling the data by either transferring it in the assignment operator or by using something like a std::unique_ptr and making sure that it is assigned (which by default transfers ownership).
Related
New to C++. Here is my code:
#include <string>
#include <cstdlib>
#include <time.h>
using namespace std;
const int Gardensize = 20;//Garden size, a 20X20 2d array
const int initialants = 100;//100 initial ants
const int initialdoodlebug = 5;//5 intial bug
const int antType = 1;//
const int doodleType = 2;//
const char antchar = 'O';//ant will display'O'in the window
const char bugchar = 'X';//
class Garden;
class Organism;
class Ant;
class Doodlebug;
class Garden {
friend class Organism;
friend class Ant;
friend class Doodlebug;
public:
Garden();
~Garden();
int checkType(int x, int y);//check the element type (ant or bug)in the grid
void Display();
private:
Organism grid[Gardensize][Gardensize]; //C2079 'Garden::grid' uses undefined class 'Organism' I have already define the class Organism in advance,have no ideal how to fix this error.
};
Garden::Garden() { //initialize the garden, set all elements in grid to "NULL"
for (int i = 0; i < Gardensize; i++) {
for (int j = 0; j < Gardensize; j++) {
grid[i][j] = NULL; //error:subscript requires array or pointer
}
}
}
Garden::~Garden() {
for (int i = 0; i < Gardensize; i++) {
for (int j = 0; j < Gardensize; j++) {
if (grid[i][j] != NULL) {
grid[i][j] = NULL;
}
}
}
}
void Garden::Display() {
for (int i = 0; i < Gardensize; i++) {
for (int j = 0; j < Gardensize; j++) {
if (grid[i][j].getType == antType) {
cout << antchar;
}
else if (grid[i][j].getType == NULL) {
cout << ".";
}
else if (grid[i][j].getType == doodleType) {
cout << bugchar;
}
}
cout << endl;
}
}
int Garden::checkType(int x, int y) {
return grid[x][y].getType();
}
class Organism {
friend class Garden;
public:
virtual int getType() {}; //
virtual void breed() {};
virtual bool starve() {};
virtual int move( int &breedtoken) {};
protected:
int x = -1; //initial xy place
int y = -1;
Garden garden;
bool moved; //used to define whether org has moved or not
int breedtoken = 0; //used to define whether org need to breed
};
class Ant : public Organism {
public:
Ant() {}; //
Ant(int x, int y, Garden* g)//initial a ant object by define the xy place in the gardene
{
this->x = x;
this->y = y;
garden = *g;
}
~Ant() {};
virtual int getType() {
return antType;
}
virtual int move(int &breedtoken);
virtual void breed() {};
virtual bool starve() { return false; };// ant wont starve
};
int Ant::move(int& breedtoken) {
int dir = rand() % 4;// randomly select direction
switch (dir) {
case 0 :// 0move upwards
if( this->x > 0 && garden.grid[x - 1][y] == NULL ){
garden.grid[x-1][y] = garden.grid[x][y];
garden.grid[x][y] = NULL;
x--;
}
break;
case 1:// 1 move downwards
if (this->x < Gardensize - 1 && garden.grid[x + 1][y] == NULL) {
garden.grid[x + 1][y] = garden.grid[x][y];
garden.grid[x][y] = NULL;
x++;
}
break;
case 2: // 2 move leftwards
if (this->y > 0 && garden.grid[x][y-1] == NULL) {
garden.grid[x][y-1] = garden.grid[x][y];
garden.grid[x][y] = NULL;
y--;
}
break;
case 3: // 3 move to right
if (this->y < Gardensize- 1 && garden.grid[x][y + 1] == NULL) {
garden.grid[x][y + 1] = garden.grid[x][y];
garden.grid[x][y] = NULL;
y++;
}
break;
this->breedtoken += 1;
return breedtoken;
}
}
class Doodlebug :public Organism {
public:
Doodlebug() {};
Doodlebug(int x, int y, Garden* g)
{
this->x = x;
this->y = y;
garden = *g;
}
virtual int getType() {
return doodleType;
}
};
int main()
{
srand(time(NULL));//
Garden garden;
int antCount = 0; //Ant counter, used to intilize 100 ants
int DoodleCount = 0;
Ant antarray[initialants];
Doodlebug doodlebugarray[initialdoodlebug];
while (antCount < initialants) {
int x = rand() % Gardensize;
int y = rand() % Gardensize;
if (garden.checkType(x, y) == NULL) {
antarray[antCount] = Ant(x, y, &garden); //initilize 100 ants
antCount++;
}
}
while (DoodleCount < initialdoodlebug) {
int x = rand() % Gardensize;
int y = rand() % Gardensize;
if (garden.checkType(x, y) == NULL) {
doodlebugarray[DoodleCount] = Doodlebug(x, y, &garden); //用数组的模式创建100只蚂蚁
DoodleCount++;
}
}
garden.Display();//display
}
The project is not finished yet. Right now, the code can initialize 100ants and 5 bugs. It can run properly but keep showing"subscript requires array or pointer " wherever I write grid[i][j] in the for loop. and " 'Garden::grid' uses undefined class 'Organism'" when I define the "Organism grid[][]" in the Garden class. I wonder to know how can i fix these 2 errors, and what's wrong with my 2d array grid?
The problem with the 2d array is caused, because you try to create an array of Organisms, which are up to that point only declared, not defined, and so the compiler doesn't know their size and can't create an array of them. This can b fixed by reordering your classes, or by putting the class declarations in headers. You can also just replace the array with a dynamic array (double pointer), and initialize it after they have been declared.
The other error is just a consequence of the first, fix it and they will both disapear.
You should try reading some book about c or c++ first, and learn a bit about pointers, and design and structure of c++ programs
So, I have a class that takes an integer, a vector of integers, and an array of lambda functions for its constructor, like so:
class Cell {
private:
short m_State;
std::function< bool(const char) > m_func;
public:
Cell(short state, std::function< bool(const char) > func) { m_State = state; m_func = func; };
Cell() { m_State = 0; m_func = [] (char) -> bool { return false; }; };
bool operator() (const char input) { return m_func(input); };
short State() { return m_State; };
};
class Row {
private:
Cell * m_Cells;
short m_States;
public:
Row( short num_states, std::vector<short> states, std::function< bool(char) > * funcs ) {
m_States = num_states;
m_Cells = new Cell[num_states];
for (short i = 0; i < m_States; i++) {
m_Cells[i] = Cell( states[i], funcs[i] );
}
};
~Row() {
delete[] m_Cells;
m_Cells = NULL;
m_States = 0;
};
short operator[] (const char input) const {
for (short i = 0; i < m_States; i++)
if (m_Cells[i](input))
return m_Cells[i].State();
return -1;
};
};
Now, suppose I have some lambdas:
auto kIS_BETWEEN = [](char s, char e) { return [s, e](char x) -> bool { return (x >= s && x <= e); }; };
auto kIS_NOT_0_DIGIT_FUNC = kIS_BETWEEN('1', '9')
Further suppose that I have a preprocessor definition like so:
#define FUNC_TYPE(x) const std::function< bool(const char) >[x]
Now, when I try and define a Row variable:
Row x = Row( 1, {1}, (FUNC_TYPE(1)){kIS_NOT_0_DIGIT_FUNC} );
I get a "taking address of temporary array" error. What am I doing wrong and how can I fix it?
The key was to change my Row class such that:
class Row {
private:
std::vector<Cell> m_Cells;
short m_States;
public:
Row( short num_states, std::vector<short> states, std::vector< std::function< bool(char) > > funcs ) {
m_States = num_states;
for (short i = 0; i < m_States; i++) {
m_Cells.push_back(const Cell( states[i], funcs[i] ));
}
};
short operator[] (const char input) const {
for (short i = 0; i < m_States; i++)
if (m_Cells[i](input))
return m_Cells[i].State();
return -1;
};
};
Ok, so I have been thinking about this for days and I am really unsure how to approach these problems. So I need to do the following:
create a union method (i.e. union(set)) that creates a union for two sets. This method should somehow invoke the element method, a method whose specifications are mentioned below
create an operator overloaded method (+) that represents the union of sets (not sure why they are different, but that's what the specifications ask for). This method must also invoke the union method
element (int) that checks if the elements are a part of the set, I have a method below, but I am not sure if it's right
operator overload method that adds an element to a new set
If you could address at least one of these, i would greatly appreciate it, I am really struggling to understand how to address these specifications. Thanks so much for your help!
#ifndef SET_H
#define SET_H
#include <iostream>
#include <cstdlib>
#include <iomanip>
using namespace std;
class Set{
friend ostream &operator<< ( ostream &, const Set &);
friend istream &operator>> ( istream &, Set &);
public:
Set ( int = DEFAULTSIZE ); //default constructor
Set ( const Set & ); //copy constructor
Set ( int [], int, char ); //constructor passing array of integers, size, name of set
~Set(); //destructor
//assignment operator
const Set &operator= ( const Set &);
//equality operator
bool operator== ( const Set & ) const;
//inequality operator
bool operator!= ( const Set &s1) const{
return !(*this == s1);
}
//subscript operators
int &operator[] ( int );
int operator[] ( int ) const;
//methods to find union, intersection, and difference of sets
Set Union ( Set & );
Set Intersect ( Set & );
Set Difference ( Set & );
Set operator+ ( Set & ); //to represent union of two sets
Set operator^ ( Set & ); //to represent intersection of two sets
Set operator- ( Set & ); //to represent difference between two sets
bool element ( int );
private:
static const int DELIM = -999; // delimiter to signal end of input
static const int DEFAULTSIZE = 10;
int numOfElements;
int psize; //physical size of array
int *set; //pointer array to represent set
};
#endif
//SOURCE FILE
//default constructor
Set::Set ( int s ){
if ( s > 0 )
psize = s;
else
psize = DEFAULTSIZE;
//allocate an array of specified size
set = new int[ psize ];
if(!set) {
//send an error is system cannot allocate memory
cout << "Cannot Allocate Memory, exiting program... " << endl;
exit (1);
}
for ( int i = 0; i < psize; i++){
set[i] = 0;
numOfElements = 0;
}
}
//copy constructor
Set::Set ( const Set &setToCopy): psize(setToCopy.psize){
set = new int[psize];
if(!set){
cout << "Cannot Allocate Memory, exiting program..." << endl;
exit (1);
}
for (int i = 0; i < psize; i++ ){
set[i] = setToCopy.set[i];
numOfElements = psize;
}
}
Set::~Set(){
if (set)
delete [] set;
set = NULL;
}
const Set &Set::operator= ( const Set &s1 ){
if ( &s1 != this){
if (numOfElements != s1.numOfElements){
delete [] set;
psize = numOfElements;
set = new int [psize];
if (!set){
cout << "Cannot Allocate memory, exiting program..." << endl;
exit (1);
}
}
}
//assign contents of the array on the right to the contents of the array on the left
for ( int i = 0; i < psize; i++ ){
set[i] = s1.set[i];
numOfElements = psize;
}
return (*this);
}
bool Set::operator== ( const Set &s1 ) const {
bool validate = true;
if ( numOfElements == s1.numOfElements ){
for ( int i = 0; i < numOfElements; i++){
if ( set [i] != s1.set[i] ){
validate = false;
break;
}
}
}
return (validate);
}
int &Set::operator[]( int subscript ){
if ( subscript < 0 || subscript >= psize ) {
cout << " Error, exiting program... " ;
exit (1);
}
return set[subscript];
}
bool Set::element ( int n ) {
bool validate = false;
for ( int i = 0; i < psize; i++){
if ( set[i] = n )
validate = true;
}
return (validate);
}
I have tried to make my own list for C++.
I have this Class:
template <class T>
class List
{
private:
T *value, *valueHelper;
int valueSize;
public:
int size;
List()
{
valueSize = 2;
value = (T*)malloc(sizeof(T) * valueSize);
size = 0;
}
void Add(T val)
{
size++;
if (size > valueSize)
{
valueSize *= 2;
valueHelper = (T*)malloc(sizeof(T) * valueSize);
memcpy(valueHelper, value, sizeof(T) * (valueSize / 2));
free(value);
value = valueHelper;;
}
value[size - 1] = val;
}
T operator[](int P)
{
return value[P];
}
};
When I try to use it in the main it works fine to Int.
Buy to Struct it is doing problems:
struct Material
{
string materialName;
int faceNum;
int meshNum;
Material(): materialName(""), faceNum(0), meshNum(0){};
};
void main()
{
List <Material> myList = List<Material>();
myList.Add(Material());
}
I got runtime error in the class on the line:
value[size - 1] = val;
Why?
You have at least two errors in your code :
- you cannot use memcpy to move class memory from one place to another except in very few cases. a std::string is not one of these cases.
- When you call an operator= it needs that the receiver is well formed, and it means that it is construct.
You hit the second error, because the value[0] is never construct, when you call the operator=, it is filled with garbage, and most probably try to delete random pointer value.
I imagine you prefer to construct object only when it is need, just like std::vector ? So a better implementation would be :
template <class T>
class List {
int m_size;
int m_capacity;
T * m_elems;
public:
List() :
m_size(),
m_capacity( 2 ),
m_elems( (T*) malloc( sizeof(T) * m_capacity ) ) {
}
void Add( T const & val ) {
if ( m_size + 1 > m_capacity ) {
m_capacity *= 2;
T * elems = (T*) malloc( sizeof(T) * m_capacity );
for( int i = 0 ; i != m_size ) {
new ( elems + i ) T( m_elems[i] ); // copy constructor
( m_elems + i )->~T(); // manually call the destructor
}
free( m_elems );
m_elems = elems;
}
new( m_elems + m_size++ ) T( val );
}
T operator[](int P) {
assert( P < m_size );
return m_elems[P];
}
};
This is because i did not pay attention to a third error in your original code ! The operator[] need to return by reference, not by value.
T & operator[](int P) {
assert( P < m_size );
return m_elems[P];
}
You probably want the const version too
T const & operator[](int P) const {
assert( P < m_size );
return m_elems[P];
}
I played around with a lot of different forward declaration combinations, this seemed like the best one. It was the only one that compiled, until I uncommented the line
e->process( this );
And I get an error from xcode that says:
non-const lvalue reference to type 'Event::ModemSimV2' cannot bind to a temporary type 'ModemSimV2'
I don't really understand what it means, any help would be appreciated.
Thanks,
Source:
#include "ModemSimV2.h"
//xvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvx
//+++++++++++++++++++++++++++++ Event +++++++++++++++++++++++++++++
Event::Event(){
}
Event::Event( const Event &e ) {
*this = e;
}
Event::~Event( ) {
}
/*
bool Event::operator > ( const Event & rhs ) const {
return time > rhs.time;
}
bool Event::operator < ( const Event & rhs ) const {
return time < rhs.time;
}
bool Event::operator <= ( const Event & rhs ) const {
return time < rhs.time;
}
bool Event::operator != ( const Event & rhs ) const {
return time != rhs.time;
}
*/
//xvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvx
//+++++++++++++++++++++++++++++ Dialin +++++++++++++++++++++++++++++
Dialin::Dialin (int name, int tm )
: time( tm ), who( name ) {
return;
}
Dialin::Dialin ( const Dialin &d ) {
*this = d;
}
Dialin::~Dialin( ) {
}
void Dialin::process( ModemSimV2 &m ) {
}
//xvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvx
//++++++++++++++++++++++++++ EventHeap ++++++++++++++++++++++++++++
EventHeap::EventHeap( ) {
size = 0;
}
EventHeap::EventHeap( int numVals ) {
size = 0;
}
//insert
void EventHeap::push( const Event e ) {
*array[size] = e;
reIndex( size );
size++;
}
//removes the min val
Event* EventHeap::pop( ) {
Event *e = array[0];
array[0] = array[size - 1];
size--;
if( !empty( ) )
buildHeap(0);
return e;
}
//re do
void EventHeap::buildHeap( int nodeIndex ) {
int leftChildIndex, rightChildIndex, minIndex;
Event *tmp;
leftChildIndex = getLeft(nodeIndex);
rightChildIndex = getRight(nodeIndex);
if (rightChildIndex >= size) {
if (leftChildIndex >= size)
return;
else
minIndex = leftChildIndex;
} else {
if (array[leftChildIndex] <= array[rightChildIndex])
minIndex = leftChildIndex;
else
minIndex = rightChildIndex;
}
if (array[nodeIndex] > array[minIndex]) {
tmp = array[minIndex];
array[minIndex] = array[nodeIndex];
array[nodeIndex] = tmp;
buildHeap(minIndex);
}
}
//re index
void EventHeap::reIndex( int hole ) {
while( array[hole] != NULL && array[hole] < array[getParent( hole )] ) {
int pIndex = getParent( hole );
Event *temp( array[hole] );
array[hole] = array[pIndex];
array[pIndex] = temp;
hole = pIndex;
}
}
//is Empty
bool EventHeap::empty() const {
return ( size == 0 );
}
int EventHeap::getLeft( int index ) const {
return ( index * 2 ) + 1;
}
int EventHeap::getRight( int index ) const {
return ( index * 2 ) + 2;
}
int EventHeap::getParent( int index ) const {
return ( index - 1 ) / 2;
}
//xvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvx
//++++++++++++++++++++++++++ ModemSimV2 +++++++++++++++++++++++++++
// Constructor for ModemSim.
ModemSimV2::ModemSimV2( int modems, double avgLen, int callIntrvl, EventHeap e )
: freeModems( modems ), avgCallLen( avgLen ),
freqOfCalls( callIntrvl ), r( (int) time( 0 ) )
{
eventSet = &e;
nextCall( freqOfCalls ); // Schedule first call
}
// Place a new DIAL_IN event into the event queue.
// Then advance the time when next DIAL_IN event will occur.
// In practice, we would use a random number to set the time.
void ModemSimV2::nextCall( int delta ){
static int nextCallTime = 0;
static int userNum = 0;
Event *e;
Dialin d = Dialin( userNum++, nextCallTime );
*e = d;
eventSet->push( *e );
nextCallTime += delta;
}
// Run the simulation until stopping time occurs.
void ModemSimV2::runSim( int stoppingTime ){
Event *e;
while( !eventSet->empty( ) ){
e = eventSet->pop();
if ( e->getTime() > stoppingTime )
break;
e->process( this );
nextCall( freqOfCalls );
}
}
Header:
#ifndef MODEM_SIM_V2_H
#define MODEM_SIM_V2_H
#include <queue>
#include <vector>
#include <functional> // for greater()
#include <climits> // for INT_MAX
#include <iostream>
#include "random.h"
using namespace std;
//xvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvx
//+++++++++++++++++++++++++++++ Event +++++++++++++++++++++++++++++
class Event{
protected:
int who; // the number of the user
int time; // when the event will occur
int what; // DIAL_IN or HANGUP
class ModemSimV2;
public:
Event( );
Event( const Event &e );
virtual ~Event( );
bool operator > ( const Event & rhs ) const;
bool operator < ( const Event & rhs ) const;
bool operator <= ( const Event & rhs ) const;
bool operator != ( const Event & rhs ) const;
int getTime( ) { return time; };
virtual void process( ModemSimV2 &m ) = 0;
};
class Dialin : public Event{
public:
Dialin( int name = 0, int tm = 0 );
Dialin( const Dialin &d );
~Dialin( );
virtual void process( ModemSimV2 &m );
private:
int who;
int time;
int what;
};
//xvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvx
//++++++++++++++++++++++++++ EventHeap ++++++++++++++++++++++++++++
class EventHeap{
public:
EventHeap();
EventHeap( int numIndex );
bool empty( ) const;
const int & findMin( ) const;
void push( const Event x );
Event * pop();
private:
int size; // Number of elements in heap
vector <Event*> array; // The heap array
void buildHeap( int index );
void reIndex( int hole );
int getLeft( int index ) const;
int getRight( int index )const;
int getParent( int index )const;
};
//xvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvxvx
//++++++++++++++++++++++++++ ModemSimV2 +++++++++++++++++++++++++++
class ModemSimV2{
public:
ModemSimV2( int modems, double avgLen, int callIntrvl, EventHeap e );
// Add a call to eventSet at the current time,
// and schedule one for delta in the future.
void nextCall( int delta );
// Run the simulation
void runSim( int stoppingTime );// = INT_MAX );
friend class Event;
private:
Random r; // A random source
EventHeap *eventSet; // Pending events
// Basic parameters of the simulation
int freeModems; // Number of modems unused
const double avgCallLen; // Length of a call
const int freqOfCalls; // Interval between calls
};
#endif
The problem is you put your forward declaration in the wrong place in the header. The process method thinks that ModemSimV2 belongs to Event, hence Event::ModemSimV2 in the error message. Move class ModemSimV2; out of the protected section to up above the class.
class ModemSimV2;
class Event
{
...
Also this is a pointer to ModemSimV2 and you need to dereference it before passing it to process.
e->process(*this);