After converting my 2D array to a 2D vector (due to all the praise I heard about it), my program breaks almost immediately, and after some testing, it appears to happen when the program tries to do a function with a vector element. I have made some simplified source code, which also has the error:
#include <iostream>
#include <vector>
using namespace std;
class Dog
{
private:
int mass, size;
public:
void setMass(int);
void setSize(int);
int getMass();
int getSize();
};
void Dog::setMass(int newMass) {mass = newMass;}
void Dog::setSize(int newSize) {size = newSize;}
int Dog::getMass() {return mass;}
int Dog::getSize() {return size;}
int main()
{
vector <vector<Dog*> > dogs(10, vector<Dog*> (10));
dogs[0][0]->setMass(10);
dogs[0][0]->setSize(5);
return 0;
}
I also have a link to Ideone, so it is easier to test (and where I tested the code) http://ideone.com/e.js/mqVuv3
You have a 2D vector of pointer-to-Dog but are not allocating any Dog objects. When you initialize the 2D vector the pointers are initialized to nullptr. Dereferencing a nullptr is undefined behaviour.
Unless you have a good reason not to, I suggest you just have a 2D vector of Dogs:
vector<vector<Dog>> dogs(10, vector<Dog>(10));
Then you will have 100 default constructed Dogs and you can happily set their mass and size:
dogs[0][0].setMass(10);
dogs[0][0].setSize(5);
Related
I have a class which is basically a wrapper for a 2D matrix of pointers to another object, and the matrix is made of vectors.
For some reason, the program crashes whenever the destructor of my class is being called, and it seems like it's trying to delete the pointers even if they are nullptr, which causes a crash.
Here are my .h and .cpp file:
cpp file:
RotationSolution.h:
#ifndef PUZZLESOLVER_ROTATIONSOLUTION_H
#define PUZZLESOLVER_ROTATIONSOLUTION_H
#include <vector>
#include <fstream>
#include "PuzzlePiece.h"
using namespace std;
class RotationSolution {
private:
int _height, _width;
vector<vector<PuzzlePiece*>> _matrix;
public:
RotationSolution();
RotationSolution(int height, int width);
vector<PuzzlePiece*>& operator[](int row);
int get_height() const;
int get_width() const;
};
#endif //PUZZLESOLVER_ROTATIONSOLUTION_H
RotationSolution.cpp:
#include "RotationSolution.h"
vector<PuzzlePiece*>& RotationSolution::operator[](int row) {
return _matrix[row];
}
RotationSolution::RotationSolution() : RotationSolution(0, 0) {}
RotationSolution::RotationSolution(int height, int width) :
_height(height), _width(width), _matrix(vector<vector<PuzzlePiece*>>(_height, vector<PuzzlePiece*>(_width, nullptr)))
{}
int RotationSolution::get_height() const {
return _height;
}
int RotationSolution::get_width() const {
return _width;
}
The code is actually crashing in a section that looks like this:
for (auto length: _rowLengths) {
auto height = size / length;
_sol = RotationSolution(height, length);
...
}
in the second iteration in the _sol = RotationSolution(height, length); line.
When debugging, the code the sends the crash signal is from new_allocator.h (which I'm pretty sure is a lib file):
// __p is not permitted to be a null pointer.
void
deallocate(pointer __p, size_type)
{ ::operator delete(__p); }
I am still new to c++ so please forgive any noob mistakes and bad practices :)
there is a design flaw in RotationSolution class - it contains member variable _matrix which stores raw pointers and it misses properly defined assigment operator which will clone objects stored inside _matrix. Default generated copy assigment operator will just copy pointers which may lead to double freeing memory and crash (here is some explanations what is happening and why). Try to use "vector< vector< std::shared_ptr< PuzzlePiece > > > _matrix" (also do #include "memory") it should fix most of problems with wrong memory management. Here is tutorial to read about smart pointers.
I am new to c++ STL and am learning from ebooks and online sources. I wanted to create a list of objects, initialise them using ::interator and list.insert() and finally display the values stored in each object.
Here is the code:
#include <iostream>
#include <list>
#include <algorithm>
#define MAX 50
using namespace std;
class numbers{
int a;
int b;
int c;
int sumvar;
int sum()
{
return(sumvar=a+b+c);
}
public:
numbers(int a,int b,int c)
{
this->a=a;
this->b=b;
this->c=c;
}
void display()
{
cout<<a<<endl<<b<<endl<<c<<endl<<endl;
}
};
int main()
{
list<numbers> listofobjects;
list<numbers>::iterator it=listofobjects.begin();
for(int i=1;i<MAX-1;i++)
{
int j=i*21-4;
int k=i*j/7;
numbers *temp = new numbers(i,j,k); //i went through a two step initialise
numbers n=*temp;
listofobjects.insert(it,n);
it++;
}
for(it=listofobjects.begin();it!=listofobjects.end();it++)
{
it->display();
}
}
So I have 2 questions:
1) Did I initialise objects correctly?
2) When I ran the program, the program output started from 32. Shouldn't it start from 1?
No you did not initialize the list correctly. Your code leaks memory.
Your code:
1) Allocates a new instance of the numbers class using new.
2) Makes a copy of the instantiated object
3) Inserts the copy object into the std::list.
So, the new-ed object gets leaked. The only thing you needed to do was:
listofobjects.insert(it, numbers(i, j, k));
Now, as far as the reason why the order was wrong, it's because of a related reason -- the iterator for the insert position is not being incremented correctly. Your insertion should be:
it = ++listofobjects.insert(it, numbers(i, j, k));
I have a small problem with std::sort.
When I try to sort an allocated array of objects using the override of the "<" function with std::sort, I get a segmentation fault.
You can see the problem here below in a toy example: In my class point, I allocate an array of personal objects key (especially I allocate the memory for an array v). Its elements are initialized, and then I try to sort this array.
With small sizes (for the array v and the array to sort), I get no error, and valgrind returns none.
For big sizes, I get a segmentation fault, and valgrind outputs a lot of errors I don't understand.
Could you help me?
Thanks!
using namespace std;
#include <stdlib.h>
#include <iostream>
#include <algorithm>
class key
{
public :
int size;
double *v, f;
key() {}
key(const key & k)
{
size = k.size;
f = k.f;
v = (double*)malloc(size*sizeof(double));
for(int i=0;i<size;i++)
v[i]=k.v[i];
}
~key()
{
free(v);
}
bool operator<(const key& other) const
{
return f<other.f;
}
void init(int s)
{
size = s;
v = (double*)malloc(size*sizeof(double));
for(int i=0;i<size;i++)
v[i]=((double)rand()/(RAND_MAX));
}
};
class point
{
public :
key *k;
point() {}
point(int param1, int param2)
{
k = (key*)malloc(param1*sizeof(key));
for(int i=0;i<param1;i++)
{
k[i].init(param2);
k[i].f=param1-i;
}
std::sort(k,k+param1);
free(k);
}
};
int main(int argc, char **argv)
{
point p(100,21200); // segmentation fault!
//point p(10,2); // no segmentation fault!
return 0;
}
Your classes need a copy constructor (or a move constructor) and a custom assignment operator because they manage raw pointers (resources). Otherwise when std::sort performs assignments of your point or key objects, the corresponding objects' data is not deep copied, but only the pointers are copied. Your destructor then ends up freeing the memory for pointers that point to the same memory address, which results in undefined behaviour (you'll often get a segfault on Linux/Unix). Also, remove those malloc/frees and replace them by new[]/delete[]. Or better, use standard containers like std::vector.
Note that some compilers can catch this issues at compile time. For example, gcc with -Weffc++ spits out an warning:
warning: struct Foo has pointer data members [-Weffc++]
but does not override Foo(const Foo&)
Can you tell why does this generate segmentation error? Problem seems to occur when operator[] is called and when I don't call it, goes fine. operator[] is supposed to return a reference to the element with index i.. any help would be great..
//dynamic_array.cpp file
#include <iostream>
#include "dynamic_array.h"
using namespace std;
dynamic_array::dynamic_array() {
int *array;
array=new int[4];
array[0]=3;
size = 4;
allocated_size = 5;
}
dynamic_array::~dynamic_array() {
delete [] array;
}
int dynamic_array::get_size(void) const {
return size;
}
int dynamic_array::get_allocated_size(void) const {
return allocated_size;
}
int& dynamic_array::operator[](unsigned int i) {
return array[i];
}
//test.cpp file
#include <iostream>
#include <stdlib.h>
#include "dynamic_array.h"
using namespace std;
int main() {
dynamic_array a;
cout << a[0];
}
//dynamic_array.h file
using namespace std;
class dynamic_array {
public:
enum {
BLOCK_SIZE = 5,
SUBSCRIPT_RANGE_EXCEPTION = 1,
MEMORY_EXCEPTION = 2,
};
dynamic_array();
~dynamic_array();
int get_size(void) const;
int get_allocated_size() const;
int& operator[](unsigned int i);
class exception {
public:
exception(int n0) { n = n0; };
int n;
};
private:
int *array; // pointer to dynamically allocated memory
int allocated_size; // total number of elements in allocated memory
int size; // number of active elements
};
The local declaration
int *array;
shadows the member array. So the following code uses the local variable, not the member. Hence the member is uninitialized.
Instead of creating your own dynamic array, use std::vector.
That's safer and more convenient.
In other news:
The get prefix in e.g. get_size is a Java-ism.
In C++ a get prefix has no advantage, and it makes the code less readable. For example, standard library containers have a size method, not a get_size.
Using void as a formal argument declaration, as in get_size(void), is a C-ism.
In C it has the important effect of telling the compiler that there really are no arguments, as opposed to any arguments. In C++ () indicates that.
Not having also a const version of operator[] is inconsistent with earlier use of const.
Consistency is very important in programming. Our expectation, e.g. when maintaining code, is that it's consistent. Code that's inconsistent adds costly man-hours to maintenance.
The ALL UPPERCASE identifiers for constants are a Java-ism.
Java lacks a preprocessor, and inherited the all uppercase convention from early C, which lacked const. C++ has both const and a preprocessor. Having const there's generally no need to use #define for constants (as in early C), and having a preprocessor there's a good tecnical reason to not use all uppercase (it conflicts with the convention for macro names). In addition many/most programmers see all uppercase as shouting. It hurts.
The class exception should better be derived from std::exception.
Instead of inventing one's own exception class that can carry an error code, just use std::system_error. That's what it's for. Alternatively, derive a class from std::runtime_error, or use std::runtime_error directly.
The problem is in your constructor
Go like this for the constructor:
dynamic_array::dynamic_array() {
array = new int[4];
array[0] = 3;
size = 4;
allocated_size = 5;
}
the problem is this additinal line of code in the constructor:
int *array;
In your constructor definition, you declared a new local pointer variable named array and you allocated memory for that.
But this variable is local to the constructor and it is not the one declared in your class as may be you believed.
Sorry for the confusing title, basically I have created two classes, one is an object, and the other being a box that contains an array of such objects. so what I want to do is create a function/constructor inside the object class that takes in an array of ints and stores them inside the box. I want to be able to call this function through the box class constructor to initialize these objects. So ive tried something like below but it isnt working at all, since only the first value of the array gets passed through. What am I doing wrong?
#include <iostream>
#include <string>
class object{
string objectName;
int values[];
public:
void createObject(int[]);
}
class Box{
object objects[100];
public:
Box();
}
Box::Box (void){
int array1[2];
int array2[15];
object[1].createObject(array1);
object[2].createObject(array2);
}
Object::Object(int Values[]){
values = Values;
}
You should really use std::vector. The problem with arrays is that they decay to pointers when passed as arguments to functions. As a consequence, If you want to store a private copy of the elements you are forced to use heap-allocated objects and consequently do memory management by hand (with all the pain it causes).
It is much better to rely on data members that permit applying the rule of zero.
Here's a tentative solution:
#include <iostream>
#include <string>
#include <vector>
class object {
public:
object(std::vector<int> const& v, std::string const& object_name): v_(v.begin(), v.end()), object_name_(object_name) {}
private:
std::vector<int> v_;
std::string object_name_;
};
class box {
public:
box(std::vector<object> const& objects): objects_(objects) {};
private:
std::vector<object> objects_;
};
I recommend you instead use a std::vector. Arrays don't really work well being passed to functions. When you define Object::Object(int Values[]) you are simply passing the first element of this array by value. If you were to use vectors, the function would look like this:
Object::Object(std::vector<int> &Values):
values(Values)
{
}
The problem with the code is in your thinking on what the array is. In C++, all an array is, is a memory pointer. The language allows you to pass an index into the array pointer to access whatever chunk of data lives at that index.
Whenever you pass arrays between functions or classes, pass the array name only. It will be interpreted as a pointer, and won't copy any data. When you do this, you must also pass the length of the array.
Granted, most people stick with vector<> because it's easier, takes care of memory leaks (mostly) and is VERY efficient. But I like doing it myself. It's good for you. I would try:
#include <iostream>
#include <string>
class Object
{
string _objectName;
int *_values;
int _myLength;
Object();
~Object();
void createObject(int *pValues, int arrLength);
}
class Box
{
_Object objects[100];
Box();
}
Box::Box(void) {
int array1[2];
int array2[15];
object[1].createObject(array1, 2);
object[2].createObject(array2, 15);
}
Object::Object() {
_values = null_ptr;
_myLength = 0;
}
Object::~Object() {
delete[] _values;
}
void Object::createObject(int *pvalues, int arrLength) {
_myLength = arrLength;
_values = new int[_myLength];
for(int ndx=0; ndx<arrLength; ndx++) {
_values[ndx] = pvalues[ndx];
}
}
-CAUTION-
I just adapted your code you provided, and added some conventions. There are a couple places in the code where I'm not sure what the purpose is, but there you go. This should give you a good head start.