This is a simplified version of what I want to do, it crushes when push_back is called, specifically when the destructor is called. If I delete the body of the destructor it works, but I want to be sure that it is deleted. Instead of calloc/free I tried new/delete with the same result. What do I do wrong here?
#include <cstdlib>
#include <vector>
using namespace std;
class Buffer
{
public:
float *DATA;
Buffer(int length) {DATA = (float*) calloc (length,sizeof(float));};
virtual ~Buffer(){free (DATA);};
private:
};
int main(int argc, char** argv)
{
vector <Buffer> v;
for (int i =0; i<10; i++)
v.push_back(Buffer(1000));
return 0;
}
Here's a working code: https://godbolt.org/z/ex9oMG.
#include <cstdlib>
#include <vector>
using namespace std;
class Buffer
{
public:
float *DATA;
Buffer(int length) {DATA = (float*) calloc (length,sizeof(float));};
Buffer(const Buffer &buffer) = delete;
Buffer(Buffer&& buffer) {
DATA = buffer.DATA;
buffer.DATA = nullptr;
}
~Buffer(){
if (DATA) free(DATA);
};
private:
};
int main(int argc, char** argv)
{
vector <Buffer> v;
for (int i =0; i<10; i++)
v.push_back(Buffer(1000));
return 0;
}
You need to define a move constructor here, primarily because v.push_back(Buffer(1000)) requires a move op otherwise the deletion of the original copy would free the resource.
I've explicitly deleted the copy ctor because when handling such resources - copy should not be allowed.
Related
I have 2 classes.
First Class - Midgam - The constructor has the following line:
midgam = new Vector[20];
The second class - Vector - where I create an array named array.
The program works great just that I have a little problem.
At the end of the program I try to print in alphabetical order, I use the BubbleSort sorting. The sorting works fine but something in the Swap function stops.
This is how it looks:
void Midgam::Swap(Vector *xp, Vector *yp) {
Vector temp = *xp;
cout << temp.getName() << endl;
*xp = *yp;
*yp = temp;
}
void Midgam::bubbleSort() {
int i, j;
for (i = 0; i < iterator - 1; i++) {
for (j = 0; j < iterator - i - 1; j++) {
if (midgam[j].getName().compare(midgam[j+1].getName()) > 0) {
Swap(&midgam[j], &midgam[j+1]);
}
}
}
}
I work with Visual Studio, the program stops and the program shows me the following code snippet in the Vector class:
Vector::~Vector() {
if (array)
delete[] array;
}
full definitions of Midgam:
#include <iostream>
#include <string>
#include "Vector.h"
using namespace std;
#ifndef MIDGAM_H_
#define MIDGAM_H_
class Midgam {
private:
int boxNum;
int maxParties;
int iterator;
Vector *midgam;
public:
Midgam(int num_of_boxes, int num_of_parties);
virtual ~Midgam();
void Start();
void Menurmal();
void SumOfEzor();
double SumOfParty(string name);
int SumAllVotes();
void AddParty();
void Swap(Vector *xp, Vector *yp);
void bubbleSort();
void Histograma();
void PrintStars(int num);
int FindPartyByName(string party);
void PrintAll();
};
#endif /* MIDGAM_H_ */
full definitions of Vector:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
#ifndef VECTOR_H_
#define VECTOR_H_
class Vector {
private:
string name;
int size;
unsigned int *array;
bool Bool;
public:
Vector(string name, int size);
Vector();
Vector & operator=(const Vector &);
virtual ~Vector();
bool StringToArray(string str);
bool getBool();
string getName();
unsigned int getAddress();
int getSize();
unsigned int getValueFromArray(int index);
double sumOfArray();
void PrintArray();
};
#endif /* VECTOR_H_ */
Does anyone know why it does not work? Thank you
Your Vector lacks a proper copy constructor.
Vector temp = *xp;
//NOT EQUAL TO:
//Vector temp;
//temp=*xp;
The above statement won't call operator=(const Vector &) even though there's an equal sign. The following line is correct and equivalent:
Vector temp(*xp);
The reason is that this is a copy initialization - temp is created and so a constructor must be called - in particular the copy constructor Vector(const Vector &). Which you did not explicitly declared and so a default one was used.
Then a shallow copy is made, temp and *xp then share the same array and when both their destructors get called the second one will try to delete already deleted memory - undefined behavior which triggers Visual Studio's debugger (at least in debug mode).
The solution is to do a proper deep copy - create a new array and copy its contents:
#include <algorithm> #Contains std::copy_n
Vector::Vector(const Vector& other)
{
name=other.name;
size=other.size;
//Creates a new array
array= new unsigned int[size];
//Copies the array contents
std::copy_n(other.array,size,array);
Boo=other.Bool;
}
Also this is a prime example of why not to use raw memory. I get that you are implementing custom vector and don't want to use std::vector for the array but at least use std::unique_ptr. If you would have just done that you wouldn't have to ask this question in the first place as the compiler would have complained and the debugger wouldn't have to do the compiler's job.
Below are 2 pieces of programs from the "Intro to C++" by MIT Open Courseware, problem 2.5 and 2.6 of assignment 3.
Both are supposed to have logical errors. However I couldn't spot any even by using a computer. There weren't any errors generated, the results also looked normal.
Anyone could spot anything abnormal in them?
This is problem 2.6:
#include <iostream>
using namespace std;
class Point{
private:
int x,y;
public:
Point(int u, int v) : x(u), y(v){}
int getX() {return x;}
int getY() {return y;}
};
int main(int argc, char *argv[]) {
Point *p = new Point(5,3);
cout<<p->getX()<<' '<<p->getY()<<endl;
return 0;
}
This is problem 2.5:
#include <iostream>
using namespace std;
int main(int argc, char *argv[]) {
int size;
cin >> size;
int* nums = new int[size];
for (int i = 0; i < size; ++i) {
cin >> nums[i];
cout << nums[i];
}
delete nums;
}
The problem 2.6 misses 'delete p;'. The problem 2.5 should have 'delete []num;' instead of 'delete num;'. Both problems introduce a memory leak.
I'm not sure, but I see the following problems:
Memory is not freed. "delete p;" should be called at the end
Incorrect variant of "delete" is called. You should use "delete[] nums;" to free memory allocated for arrays.
Testing legacy code.
If I write a test for a method that takes an int[] as parameter, I use unique_ptr so I don't have to care for cleaning up allocated memory:
#include <memory>
bool methodToTest(int *parameter)
{
bool result = true;
// doing stuff
return result;
}
int main(int argc, char* argv[])
{
std::unique_ptr<int[]> input(new int[99]);
methodToTest(input.get());
// ASSERT(blah, blah)
return system("pause");
}
Can I do something similar for a function that takes an int[][]? Like
#include <memory>
#include <vector>
bool methodToTest(int **parameter)
{
bool result = true;
// doing stuff
return result;
}
int main(int argc, char* argv[])
{
//std::unique_ptr<int[][]> input; // Compiler complains: error C2087: 'abstract declarator' : missing subscript
//std::unique_ptr<std::unique_ptr<int[]>[]> input; // Nice structure, but how to get an int[][] from that?
std::vector<int*> input; // Works but I have to manually free allocated memory
methodToTest(input.data());
// ASSERT(blah, blah)
return system("pause");
}
So, do I have to care for freeing allocated memory myself or is there some std:: way that does that for me?
I found something myself and suggest:
#include <memory>
bool methodToTest(int **parameter)
{
bool result = true;
// doing stuff
return result;
}
int main(int argc, char* argv[])
{
std::unique_ptr<int*[]> input(new int*[44]);
std::unique_ptr<int[]> inner_input(new int[89]);
input[3] = inner_input.get();
methodToTest(input.get());
// ASSERT(blah)
return system("pause");
}
Note that inner_input have to be a vector of unique_ptr if you want more than one of them.
This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 8 years ago.
I know this is a common error so I tried to create a minimal example. I think this is because I try to free stack memory but I don't quite understand how I could do differently.
Maze.h
#pragma once
class Maze
{
public:
Maze();
Maze(unsigned int height, unsigned int width);
~Maze();
private:
unsigned int m_height;
unsigned int m_width;
char *entrance;
char *exit;
char *m_cells;
};
Maze.cpp
#include "Maze.h"
using namespace std;
Maze::Maze()
{
}
Maze::Maze(unsigned int height, unsigned int width) :
m_height(height),
m_width(width)
{
m_cells = new char[m_height * m_width];
entrance = nullptr;
exit = nullptr;
}
Maze::~Maze()
{
delete entrance;
delete exit;
delete[] m_cells; //this line causes the error
}
main.cpp that causes an error
#include <iostream>
#include <string>
#include "Maze.h"
using namespace std;
int __cdecl main(int argc, char **argv)
{
Maze maze;
maze = Maze(10, 10);
}
main.cpp without error
#include <iostream>
#include <string>
#include "Maze.h"
using namespace std;
int __cdecl main(int argc, char **argv)
{
Maze maze(10, 10);
}
What are the differences between the 2 mains ? why does the first one cause an error ? This is a problem because I want to declare maze but to initialize it later in my program. Here I only do it in two lines to create a minimal example.
The error occurs when the program closes so I think it's a memory deallocation problem. Indeed, when I remove
delete[] m_cells;
from the destructor, no error anymore.
What's happening exactly here ?
The line:
maze = Maze(10, 10);
Is creating a copy of the object, so what happens is:
Maze(10, 10) - constructs a new object, who allocates memory with operator new and operator new[].
maze is assigned a copy of the object made in 1. This is done by simply assigning the pointer values of the first to the 2nd.
Then the object from 1 is destructed, it deletes the pointers.
maze eventually goes out of scope, it deletes the pointers again, here you crash.
To solve this read about the rule of 3, you need to add a copy constructor and an assignment operator.
For example:
// This the copy constructor
Maze::Maze(const Maze& other)
{
// Call the assignment operator, saves duplicating the assignment operator code in here.
*this = other;
}
// This is the assignment operator
Maze& Maze::operator = ( const Maze& other )
{
if ( this != &other )
{
// TODO: Copy your pointers, not by assigning them, but use operator new and copy the data as "other" will destruct and delete those pointers, hence your problem
}
return *this;
}
If you are using C++11 you could also use move construction/assignment too, then you would simply swap the pointers, and set the source objects pointers to NULL/nullptr.
In C++11 you can also use the default and delete keyword to prevent use of constructors you have no implemented that shouldn't be called, for example:
class Foo
{
public:
Foo() = default;
// Prevent copying
Foo(const Foo&) = delete;
Foo& operator = ( const Foo& ) = delete;
int x = 0;
};
This would cause the following to fail at the compilation stage:
Foo a;
a = Foo();
again this question is also origined from "Thinking in C++" Chapter7, Q#7. I believe the Stack header file should be changed to Stack.h
#ifndef STACK_H
#define STACK_H
class Stack {
struct Link {
void* data;
Link* next;
Link(void* dat, Link* nxt);
~Link();
}* head;
public:
Stack();
Stack(void* arr[], int size);
~Stack();
void push(void* dat);
void* peek();
void* pop();
};
and the implementation of Stack::Stack(void* arr[], int size) in Stack.cpp, I believe could be like:
Stack::Stack(void* arr[], int size)
{
for (int i=0; i<size; i++)
{
push(arr[i]);
}
}
However, in the main test file StackTest.cpp, how could I pass the address of a string array to this constructor? Here is what I come up with:
#include "Stack.h"
#include "require.h"
#include <iostream>
#include <string>
using namespace std;
int main() {
string tst_arr[] = {"hi 1", "hi 2", "hi 3"};
Stack string_arr((void**)tst_arr, 3);
string* s;
while((s = (string*)string_arr.pop()) != 0) {
cout << *s << endl;
delete s;
}
}
But it has some segmentation fault. What I could think of is to change Stack::Stack(void* arr[], int size) to Stack::Stack(string arr[], int size), however it doesn't satisfies the question requirement. The purpose of Stack to store generic objects, including string for example. I believe I still have difficulty to understand the conceipt of void* pointer and array of pointers and the chagne between string array to void* array etc... Anyone could help me solve this problem? Thanks a lot!!
Your Stack constructor asks for an array of pointers on stuffs, and you give it an array of objects. As a bonus, I give you proper main function and freeing memory ^^
#include <cstdlib>
// --- Includes your stuffs ---
using namespace std;
int main(int argc, char* argv[]) {
string* tst_arr[] = new string[3];
tst_arr[0] = new string("hi 1");
tst_arr[1] = new string("hi 2");
tst_arr[2] = new string("hi 3");
Stack string_arr((void**)tst_arr, 3);
// --- Do your stuffs ---
for(int i =0; i < 3; ++i)
delete tst_arr[i];
delete[] tst_arr;
return EXIT_SUCCESS;
}