stable_sort on objects containing dynamic tables - c++

I have a problem with sorting. I sort the objects containing the dynamic table. It seems that the stable_sort (or the vector) doesn't use a public copy constructor. I looks like they use a non-existent constructor with no parameter because the tables inside the objects are freed - I think.
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
class Dynamic{
int n;
int *tab;
public:
int getN() const{ return n;}
int *getTab() const {return tab;}
Dynamic(int ile){
n=ile;
tab=new int[n];
for(int i=0; i<n; i++)
tab[i] = (10-i)%10;
}
Dynamic(const Dynamic& d){
n = d.getN();
tab = new int[n];
for(int i=0; i<n; i++)
tab[i] = d.getTab()[i];
}
bool operator<(const Dynamic& a) const{
return n < a.getN();
}
~Dynamic(){
delete[] tab;
}
};
int test(vector<Dynamic> & c){
vector<Dynamic> d(c);
stable_sort(d.begin(), d.end());
d.clear();
}
int main(){
vector<Dynamic> c;
c.push_back(Dynamic(15));
test(c);
cout<<"test!";
return 0;
}
STL's sort is also affected but in slightly more complex way.
In g++-4.7.2 I can compile this and in running I get "double free or corruption (fasttop)"/core dumped (full report isn't helpful, I think). On online g++-4.9.0 it looks similar: "No output: Error: stdout maxBuffer exceeded.".
Where is my mistake? Thank you for your attention.

Well, you didn't overload the operator= for Dynamic, so the compiler implicitly defines one which would do bitwise copy. stable_sort() in your library calls the operator=, so tab in two Dynamic objects points to the same address, as a result, double delete on destruction. Overloading the operator= would resolve the problem:
Dynamic& operator =(const Dynamic& d)
{
// or use the copy-and-swap idiom
if(this != &d)
{
delete [] tab;
n = d.getN();
tab = new int[n];
for (int i = 0; i<n; i++)
tab[i] = d.getTab()[i];
}
return *this;
}

Related

Core Dumped due to delting an array

I'm trying to make a copy constructor with low level arrays and I'm getting a core dumped error when using delete, can't find out a solution because I'm not able to use std::vector to make this.
Can you guys help me ?? =)
#include<iostream>
#include<string>
#include<initializer_list>
class Vector{
size_t n;
double* datos;
public:
Vector(size_t n_,double);
Vector(const std::initializer_list<double>&l);
void show();
~Vector(){
delete[] datos;
}
Vector(Vector&& other):n(other.n){
delete [] datos;
datos =other.datos;
other.datos =nullptr;
}
Vector(const Vector& v);
Vector operator = (const Vector& v);
};
/* --------------------------- METODOS DE LA CLASE -------------------------- */
Vector::Vector(const Vector&v){
delete[]datos; //CORE DUMPED
n=v.n;
datos = new double[n];
for (size_t i = 0; i < n; i++)
{
datos[i] = v.datos[i];
}
std::cout<<std::endl;
}
Vector Vector::operator = (const Vector& v){
delete [] datos;//CORE DUMPED
n = v.n;
for (size_t i = 0; i < n; i++)
{
datos[i] = v.datos[i];
}
return *this;
}
Vector::Vector(const std::initializer_list<double>&l):n(l.size()),datos(new double[n]){
size_t j= 0;
for (auto i:l)
{
datos[j]=i;
++j;
}
}
void Vector::show(){
for (size_t i = 0; i < n; i++)
{
std::cout<<datos[i]<<", ";
}
std::cout<<std::endl;
}
Vector::Vector(size_t n_,double d=0):n(n_),datos(new double[n]){
if (n < 1)
{
throw std::invalid_argument("Wrong size!");
}
for (size_t i = 0; i < n; i++)
{
datos[i] = d;
}
}
int main(){
Vector b={2,3,4,5,6},a(3);
a=b;
a.show();
}
Using POP OS 21.04 (just in case this can help).
Please don't be rough with me I'm a junior programmer trying to pass September's exams =(
Vector::Vector(const Vector&v){
delete[]datos; //CORE DUMPED
You didn't initialise datos, so its value is indeterminate. When you delete an indeterminate pointer, then the behaviour of the program is undefined. "CORE DUMPED" is one possible behaviour that you may observe.
You are issuing unneeded calls to delete [] datos in your constructors (move and copy).
Since datos is uninitialized, calling delete [] on an uninitialized pointer leads to undefined behavior -- in your case, your program crashes.
Since the objects are being constructed, there is no reason to issue a delete [] on the pointer, since the object this is brand new.
Simply remove the call to delete [] datos; from the constructors. Whether this is the only problem is another story, but it is an existing one.
In addition, your assignment operator:
Vector Vector::operator = (const Vector& v)
is also incorrect. It fails to allocate new memory after the delete [] call, thus the for loop that is written will write into unallocated memory. Also, it should return a reference to the current Vector object, not a brand new Vector object.
The easiest way to implement the assignment operator is to use std::swap:
#include <algorithm>
//...
Vector& Vector::operator = (Vector v)
{
std::swap(v.datos, datos);
std::swap(v.n, n);
return *this;
}
This assumes you have a working, non-buggy copy constructor and destructor for Vector. See the copy / swap idiom for details on why this works.

Finding Bug in implementation of dynamic array class. Crashes after building list of strings

I have written a DynamicArray class in the past analogous to vector which worked.
I have also written as a demo, one where the performance is bad because it has only length and pointer, and has to grow every time. Adding n elements is therefore O(n^2).
The purpose of this code was just to demonstrate placement new. The code works for types that do not use dynamic memory, but with string it crashes and -fsanitize=address shows that the memory allocated in the addEnd() method is being used in printing. I commented out removeEnd, the code is only adding elements, then printing them. I'm just not seeing the bug. can anyone identify what is wrong?
#include <iostream>
#include <string>
#include <memory.h>
using namespace std;
template<typename T>
class BadGrowArray {
private:
uint32_t size;
T* data;
public:
BadGrowArray() : size(0), data(nullptr) {}
~BadGrowArray() {
for (uint32_t i = 0; i < size; i++)
data[i].~T();
delete [] (char*)data;
}
BadGrowArray(const BadGrowArray& orig) : size(orig.size), data((T*)new char[orig.size*sizeof(T)]) {
for (int i = 0; i < size; i++)
new (data + i) T(orig.data[i]);
}
BadGrowArray& operator =(BadGrowArray copy) {
size = copy.size;
swap(data, copy.data);
return *this;
}
void* operator new(size_t sz, void* p) {
return p;
}
void addEnd(const T& v) {
char* old = (char*)data;
data = (T*)new char[(size+1)*sizeof(T)];
memcpy(data, old, size*sizeof(T));
new (data+size) T(v); // call copy constructor placing object at data[size]
size++;
delete [] (char*)old;
}
void removeEnd() {
const char* old = (char*)data;
size--;
data[size].~T();
data = (T*)new char[size*sizeof(T)];
memcpy(data, old, size*sizeof(T));
delete [] (char*)old;
}
friend ostream& operator <<(ostream& s, const BadGrowArray& list) {
for (int i = 0; i < list.size; i++)
s << list.data[i] << ' ';
return s;
}
};
class Elephant {
private:
string name;
public:
Elephant() : name("Fred") {}
Elephant(const string& name) {}
};
int main() {
BadGrowArray<int> a;
for (int i = 0; i < 10; i++)
a.addEnd(i);
for (int i = 0; i < 9; i++)
a.removeEnd();
// should have 0
cout << a << '\n';
BadGrowArray<string> b;
b.addEnd("hello");
string s[] = { "test", "this", "now" };
for (int i = 0; i < sizeof(s)/sizeof(string); i++)
b.addEnd(s[i]);
// b.removeEnd();
cout << b << '\n';
BadGrowArray<string> c = b; // test copy constructor
c.removeEnd();
c = b; // test operator =
}
The use of memcpy is valid only for trivially copyable types.
The compiler may even warn you on that, with something like:
warning: memcpy(data, old, size * sizeof(T));
writing to an object of non-trivially copyable type 'class string'
use copy-assignment or copy-initialization instead [-Wclass-memaccess]
Note that your code do not move the objects, but rather memcpy them, which means that if they have for example internal pointers that point to a position inside the object, then your mem-copied object will still point to the old location.
Trivially Copyable types wouldn't have internal pointers that point to a position in the object itself (or similar issues that may prevent mem-copying), otherwise the type must take care of them in copying and implement proper copy and assignemnt operations, which would make it non-trivially copyable.
To fix your addEnd method to do proper copying, for non-trivially copyable types, if you use C++17 you may add to your code an if-constexpr like this:
if constexpr(std::is_trivially_copyable_v<T>) {
memcpy(data, old, size * sizeof(T));
}
else {
for(std::size_t i = 0; i < size; ++i) {
new (data + i) T(std::move_if_noexcept(old[i]));
}
}
In case you are with C++14 or before, two versions of copying with SFINAE would be needed.
Note that other parts of the code may also require some fixes.

Following program is throwing an error related memory access

/This program is using template class. I don't know why but this program is throwing an error at run time related memory access violation. in below comments i will explain which line is causing this error./
#include<iostream>
using namespace std;
const int size =3;
template <class t="">
class vector
{
T* v;
public:
vector()
{
v=new T[size];
for(int i=0;i<size;i++)>
v[i]=0;
}
vector(T* a)
{
for(int i=0;i<size;i++)>
v[i]=a[i];
}
T operator*(vector &y)
{
T sum=0;
for(int i=0;i<size;i++)>
sum+=this->v[i] * y.v[i];
return sum;
}
void display(void)
{
for(int i=0;i<size;i++)>
{
cout<<v[i]<<"\t";
}
cout<<"\n";
}
};
int main()
{
int x[3]={1,2,3};
int y[3]={4,5,6};
vector<int> v1;
vector <int> v2;
v1=x; // This is causing an error
v2=y; // This is causing an error
//int R=v1*v2;
//cout<<"R = "<<R<<"\n";
cout<<"V1 = ";
v1.display();
cout<<"V2 = ";
v2.display();
cout<<"V1 x V2 = "<<v1*v2;
return 0;
}
It seems that the problem is in this constructor
vector(T* a)
{
for(int i=0;i<size;i++)>
v[i]=a[i];
}
You did not allocate memory for the array pointed by v.
2 Problems:
You are not initializing memory for your vector
You are calling the constructor incorrecly
To fix #1
vector(T* a)
{
v=new T[size];
for(int i=0;i<size;i++)>
v[i]=a[i];
}
To fix #2
int x[3]={1,2,3};
int y[3]={4,5,6};
vector<int> v1(x);
vector <int> v2(y);
the constructor vector(T * a) will get called and the member v is not initialized with anything. This causes undefined behavior. So to fix this you need to allocate in that constructor
vector(T* a)
{
v = new T[size];//this line is new
for(int i=0;i<size;i++)
v[i]=a[i];
}
My guess is there is no operator=(int []) defined for vector.
So in other words, compiler does not know what do you mean by v1=x when it comes to type int[] = vector<int>.
You are not calling the overloaded constructor there. So you either need to call it vector<int> v1(y); or implement vector::operator=(const T[] v);
I hope i got the types right
When calling the lines in question, the program is using a default assignment operator which is doing something that causes your violation. You need to implement this yourself, for example, this worked for me:
T& operator=(T const * a)
{
for(int i=0;i<size;i++)
v[i]=a[i];
return *this;
}

copy object pointer into dynamic object array

I am working with a class I created that has a function addClass which allow the user to add A an Instance of Class to a dynamically allocated array.
Here is the code of the class and a simple test:
Class.h Listing
#ifndef CLASS_H
#define CLASS_H
#include<iostream>
class Class {
public:
Class(std::string text);
Class(const Class& orig);
virtual ~Class();
Class(std::string text, Class * name, int size);
std::string toString();
void addClass(Class * name, int size = 1);
Class getClass(int index);
private:
Class * classArray;
std::string value;
int size;
};
#endif /* CLASS_H */
Class.c Listing
#include "Class.h"
#include <cstdlib>
Class::Class(std::string text) {
classArray = NULL;
value = text;
size = 0;
}
Class::Class(const Class& orig) {/*...*/}
Class::~Class() {}
Class::Class(std::string text, Class * name, int size){
value = text;
this->size = size;
if(size == 1)
classArray = name;
else{
int i;
classArray = (Class*)malloc(size*sizeof(Class));
for(i = 0; i < size; i++){
classArray[i] = name[i];
}
}
}
std::string Class::toString(){
return value;
}
void Class::addClass(Class * name, int size){
int i;
Class * tmp = (Class*)malloc((this->size+size)*sizeof(Class));
for(i = 0; i < this->size-1; i++){
tmp[i] = classArray[i];
}
if(size == 1)
tmp[size-1] = name[0];//assignement method is the problem!!!??
else{
for(i = this->size; i < this->size+size-1; i++){
tmp[i] = name[i];
}
}
this->size += size;
free(classArray);
classArray = tmp;
}
Class Class::getClass(int index){
return classArray[index];
}
test.c Listing
#include<iostream>
#include "Class.h"
using namespace std;
int main(int argc, char** argv) {
Class * objectA = new Class("objectA");
Class * objectB = new Class("objectB");
cout << objectA->toString() << endl;
objectA->addClass(objectB);
//never gets here :'(
cout << objectA->toString() << endl;
return 0;
}
The problem is the test never gets past the objectA->addClass(objectB) instruction. I tried to debug and what I found was that the problem comes from the assignement instruction of the addClass() method. I also tried memcpy it didn't work. Does anyone have a solution for this please. Thanks.
Don't use malloc on C++ objects, use new and new[] and delete and delete[]. The problem with malloc in C++ is that it doesn't call the constructors for your objects, and free doesn't call the destructors. new, new[], delete and delete[] do. You get a crash because you are assigning to unconstructed objects and you get that because you didn't use new.
Not saying that's the only problem with your code, but it's the obvious one.
A basic solution is to prefer new and delete over malloc and free. A much better solution is to use a standard container such as std::vector to hold the elements at Class::addClass(). Let the computer take care of all that memory management; you will be saving a lot of development and debugging time.
Note that in your code you defined a custom copy constructor Class(const Class&) for your class, but you seem not having defined a copy assignment operator Class& operator=(const Class&). Note that in your code you use copy assignment (operator=) to make copies of your class, but you don't have a proper implementation of it.
Moreover, in C++ you should prefer using new[]/delete[] to C's malloc()/free(), and even better just use std::vector container for arrays.
You can also have a std::vector< SomeSmartPointer > (e.g. std::vector<std::shared_ptr<SomeClass>>, or std::vector<std::unique_ptr<SomeClass>>). In general, consider std::vector of some smart pointer, but don't use a std::vector of owning raw pointers (std::vector<SomeClass*>).

C++ Operator Overload Error

I'm trying to create my own version of an array called a safearray, to test my knowledge of operator overloading and creating proper class's and such.
I'm encountering two errors.
SafeArray.h:11:15: error: ‘const int SafeArray::operator’ cannot be overloaded
SafeArray.h:10:10: error: with ‘int& SafeArray::operator’
My code is split between three files.
Main.cpp
#include <cstdlib>
#include <iostream>
#include "SafeArray.h"
using namespace std;
int main(int argc, char** argv) {
SafeArray a(10); // 10 integer elements
for (int i = 0; i < a.length(); i++) {
cout << i << " " << a[i] << "s" << endl; // values initialise to 0
}
cout << endl << a[1]; // Program exits here.
a[3] = 42;
cout << a[3];
a[10] = 10;
cout << a[10];
a[-1] = -1; // out-of-bounds is "safe"?
SafeArray b(20); // another array
b = a; // array assignment
for (int i = 0; i < b.length(); i++) {
cout << b[i] << endl; // values copied from a
}
return 0;
}
SafeArray.h
#ifndef SAFEARRAY_H
#define SAFEARRAY_H
class SafeArray {
public:
SafeArray(int); // int variable will be the array size
int length();
int boundsCheck(int y); // constructor will call this function
// const SafeArray operator= (const SafeArray&);
int& operator[] (int y);
const int operator [] (const int y); // you need this one too.
SafeArray &operator=(SafeArray rhs) {
std::swap(array, rhs.array);
std::swap(length_, rhs.length_);
}
SafeArray(SafeArray const &other);
~SafeArray();
private:
int length_;
int *array;
//int array[];
};
#endif /* SAFEARRAY_H */
SafeArray.cpp
#include "SafeArray.h"
#include <iostream>
SafeArray::SafeArray(int x) {
length_ = x;
array = new int[length];
for (int i = 0; i < length_; i++) {
array[i] = 0;
}
}
int SafeArray::length() {
return this->length_;
}
int SafeArray::boundsCheck(int y) {
}
int& SafeArray::operator[] (int y) {
return array[y];
}
SafeArray::~SafeArray() {
delete [] array;
}
SafeArray::SafeArray(SafeArray const &other) {
int *temp = new int[rhs.size_];
for (int i=0; i<rhs.size_; i++)
temp[i] = rhs.array[i];
std::swap(temp, array);
delete [] temp;
return *this;
}
Your class definition isn't valid. int array[] is an incomplete type, which must not appear as a (non-static) class member. Some compilers accept this as a synonym for int array[0], but zero-sized arrays are not valid in C++, either (only in C99).
In short, you cannot write your code the way you do. You need to learn about dynamic allocation and manage your own memory. Check out how std::vector is implemented.
In C++11, I might recommend a std::unique_ptr<int[]> array as a quick-fix approach, to be initialized as array(new int[x]).
Actually int array[] is valid, and may appear as a class member. The following compiles with strict C++11 conformance:
class foo
{
public:
foo() {}
int length;
int A[];
};
void ralph()
{
foo *bar = (foo *)new int[ 21 ];
bar->length = 20;
bar->A[0] = 1;
}
This is legal, and has its advantages (occasionally). Although it is not commonly used.
However, I suspect that the OP wanted something more along the lines of
class SafeArray {
public:
SafeArray(int); // int variable will be the array size
int length();
int boundsCheck(int y); // constructor will call this function
int& operator[] (int y);
const int operator [] (const int y) // you need this one too.
private:
int length_;
int *array;
};
along with
SafeArray::SafeArray(int x) {
length_ = x;
array = new int[length];
for (int i = 0; i < length_; i++) {
array[i] = 0;
}
}
As #Kerrek already pointed out, your class definition is clearly wrong (shouldn't compile).
To fix it, you want to change the definition to something like:
int *array;
Then in your default ctor you could use something like this:
SafeArray::SafeArray(unsigned size = 0)
: array(new int[size])
{
for (unsigned i=0; i<size; i++)
array[i] = 0;
}
Then, yes, you'll need to write an assignment operator. The usual way is called the copy and swap idiom. You create a copy, then swap the contents of the current one with those of the copy:
SafeArray &operator=(SafeArray rhs) {
std::swap(array, rhs.array);
std::swap(length_, rhs.length_);
}
Along with that, you'll need a copy constructor that makes a copy of the data as well:
SafeArray::SafeArray(SafeArray const &other) {
int *temp = new int[rhs.size_];
for (int i=0; i<rhs.size_; i++)
temp[i] = rhs.array[i];
std::swap(temp, array);
delete [] temp;
return *this;
}
Finally, you'll need a destructor to destroy an object and (particularly) delete the memory it holds:
SafeArray::~SafeArray() {
delete [] array;
}
Then realize that all of that is an ugly mess that will never really work well. In particular, the basic methodology is restricted to an array that's basically fixed in size. As long as you only store ints, it's fairly easy to overlook the problems, and make a dynamic array that (sort of) works. When/if you want to store some other type, however, you just about need to separate allocating memory from initializing objects in that memory, which means throwing away essentially all the code above, and replacing it with something that:
keeps track of the array size and allocation size separately
allocates memory with ::operator new, an Allocator object, or something else similar
uses placement new to initialize objects in the memory when needed.
uses explicit destructor calls to destroy the objects
uses ::operator delete to release memory
and so on. To summarize, std::vector is not a trivial piece of work.
The error message refers to these two lines:
int& operator[] (int y);
const int operator [] (const int y); // you need this one too.
Your error message says that (int y) and (const int y) are too similar to be two different overloads of the [] operator. You cannot overload on (int y) and (const int y) because the calls would all be ambiguous.
You probably meant to return a const int if your SafeArray is const, but return an int& if your SafeArray is not const. In that case, you declare the second function to apply to const SafeArray, by putting the word const after the parameter list. This is what you should write in SafeArray.h:
int& operator[] (int y);
const int operator [] (int y) const; // you need this one too.
You would then have to write both of these functions in SafeArray.cpp:
int& SafeArray::operator[] (int y) {
return array[y];
}
const int SafeArray::operator[] (int y) const { // you need this one too.
return array[y];
}