Recently, I started to learn C++ after I have learned Java, and I was instructed to make a dynamic array, so I tried to make a temp variable which contains what I need and then reassign it into the variable I actually want to use.
void Pile::grow(Stone s){
Stone temp[getLength() + 1];
for (int i = 0; i < sizeof(temp) / sizeof(temp[0]); ++i) {
if (sizeof(temp) / sizeof(temp[0]) < 28){
temp[i] = stoneArr[i];
}
}
stoneArr = temp;
}
But the compiler is giving me an error that I cannot reassign it, for some reason I just can't understand.
void Pile::grow(Stone s)
You are not using s anywhere. Are you supposed to add it to the new array you are trying to create?
Stone temp[getLength() + 1];
This is not legal in standard C++. The size of a fixed array must be known at compile time.
Some compilers support "variable length arrays" as a non-standard extension, but do not rely on them if you need to write portable code. See Why aren't variable-length arrays part of the C++ standard?
To allocate an array dynamically at runtime, use the new[] operator instead, eg:
Stone *temp = new Stone[getLength() + 1];
...
delete[] temp;
Or, use the standard std::vector container instead, eg:
#include <vector>
std::vector<Stone> temp(getLength() + 1);
...
for (int i = 0; i < sizeof(temp) / sizeof(temp[0]); ++i)
You cannot use this sizeof trick on a dynamic array, let alone a VLA. sizeof is evaluated only at compile time, not at runtime.
Since you are copying values from an existing array, use the length of that array instead:
for (int i = 0; i < getLength(); ++i)
if (sizeof(temp) / sizeof(temp[0]) < 28)
Hard-coding a 28 here makes no sense. In fact, this whole if check needs to be removed completely.
stoneArr = temp;
This assignment will not work when temp is a VLA. And stoneArr can't be a VLA anyway.
stoneArr needs to be either a Stone* pointer to a new[]'d array (that is managed by following the Rule of 3/5/0), or a std::vector<Stone> (preferred).
With all of that said, try this instead:
private:
Stone *stoneArr;
int arrLength;
...
Pile::Pile()
: stoneArr(NULL), arrLength(0) {
}
Pile::Pile(const Pile &src)
: stoneArr(new Stone[src.arrLength]), arrLength(src.arrLength) {
for (int i = 0; i < arrLength; ++i) {
stoneArr[i] = src.stoneArr[i];
}
}
Pile::~Pile() {
delete[] StoneArr;
}
Pile& Pile::operator=(const Pile &rhs) {
if (&rhs != this) {
Pile temp(rhs);
std::swap(stoneArr, temp.stoneArr);
std::swap(arrLength, temp.arrLength);
}
return *this;
}
int Pile::getLength() const {
return arrLength;
}
void Pile::grow(const Stone &s){
Stone *temp = new Stone[arrLength + 1];
for (int i = 0; i < arrLength; ++i) {
temp[i] = stoneArr[i];
}
temp[arrLength] = s;
delete[] stoneArr;
stoneArr = temp;
++arrLength;
}
Or:
#include <vector>
private:
std::vector<Stone> stoneArr;
...
// std::vector follows the rule of 3/5/0, so let the
// compiler handle Pile(), Pile(const Pile &), ~Pile(),
// and operator= for you...
int Pile::getLength() const {
return stoneArr.size();
}
void Pile::grow(const Stone &s){
stoneArr.push_back(s);
}
Related
I am not sure where I am going wrong with this.
I have a Movie.h with all the data members and constructors destructors and copy constructors needed but I have a feeling it's failing at my assignment operator someone, please help
Movie& Movie::operator=(const Movie& _assign) {
// Self-assignment check
if (this == &_assign)
return *this;
// Shallow copy non-dynamic data members
mRuntime = _assign.mRuntime;
// Deep copy appropriate data members
mTitle = new char[strlen(_assign.mTitle) + 1];
strcpy_s(mTitle, strlen(_assign.mTitle) + 1, _assign.mTitle);
// Deep copy the reviews
SetStars(_assign.mStars, mNumReviews);
return *this;
}
void Movie::SetStars(const int* _stars, int _numReviews) {
// Allocate array and deep copy
mStars = new int[_numReviews];
for (int i = 0; i <= _numReviews; ++i) {
// Cap reviews between 1-10
if (_stars[i] > 10)
{
mStars[i] = 10;
}
else if (_stars[i] < 0)
{
mStars[i] = 0;
}
else
{
mStars[i] = _stars[i];
}
}
// Set the number of reviews
mNumReviews = _numReviews;
}
The problem happens here:
mStars = new int[_numReviews];
for (int i = 0; i <= _numReviews; ++i) {
Specifically here:
i <= _numReview // this causes you to go out of bounds
changing it to:
i < _numReview
resolves the issue
You are allocating _numReview items. C++ has 0-based array indexing. Elements will go from 0 to _numReview - 1
Please consider using std::string and std::vector instead of c-style arrays.
I met huge problem with memory leaks and I don't know where to put that "delete" to get rid of them. Below is part of my code, and there is a full one: https://pastebin.com/Wtk83nuH.
string* startowa(int& rozmiar)
{
rozmiar = 5;
string* tablica = new string[rozmiar];
for (int i = 0; i < rozmiar; i++)
tablica[i] = "text";
return tablica;
}
string* plusx(string* tab, int& rozmiar)
{
string tekst = "something";
string* tablica_3 = new string[rozmiar];
tablica_3[rozmiar - 1] = tekst;
for (int i = 0; i<rozmiar - 1; i++)
tablica_3[i] = tab[i];
return tablica_3;
}
string* minusx(string* tab, int& rozmiar)
{
string* tablica_3 = new string[rozmiar];
for (int i = 0; i < rozmiar; i++)
tablica_3[i] = tab[i];
return tablica_3;
}
int main()
{
int wybor = 1, rozmiar = 1;
string *tablica = startowa(rozmiar);
while (wybor != 55) {
cin >> wybor;
if (wybor == 1) {
rozmiar++;
tablica = plusx(tablica, rozmiar);
}
if (wybor == 6) wybor = 55;
else {
rozmiar--;
tablica = minusx(tablica, rozmiar);
}
// there were other "ifs" but its just a part of the code
}
for (int i = 0; i < rozmiar; i++)
cout << tablica[i] << endl;
delete[] tablica;
cin >> wybor;
getchar();
return 0;
}
The memory leak is your least problem in that source code. In fact, you don't need heap allocations at all in your example.
Here are some fast improvements:
- use "std::string" instead of just string, I guess you are using "using namespace std"
- do not return a pointer to string, you can just declare a string and return it
- do not use a reference to an int as a function parameter if you are not returning it
- use const as much as you can
- replace "string *" with "const string&" if you are not returning it
- do not allocate string on heap (with new), instead declare it on stack
- use vectors
You can use this great site and Scott Meyers books for other C++ good practices.
To prevent memory leaks like that, avoid manual memory management. There are a lot of tools available to you.
For example, take your string array:
string* startowa(int& rozmiar) {
rozmiar = 5;
string* tablica = new string[rozmiar];
// ...
}
This should be replaced by std::vector. And since a vector keep track of it's size, you don't need to pass the size as reference:
std::vector<std::string> startowa() {
// ...
std::vector<std::string> tablica(5);
// ...
}
Then, your function that operates on the array should take the vector by reference to about copies, and return another vector. Since a vector already has a function that insert a new element, your plusx function becomes this:
void plusx(std::vector<std::string>& tab) {
std::string tekst = "something";
tab.emplace_back(std::move(tekst));
}
And your minusx function becomes that:
void minusx(std::vector<std::string>& tab) {
tab.pop_back();
}
By the way, with a vector, you can completely remove your startowa function by replacing the call in your main by this:
// Was `string *tablica = startowa(rozmiar);`
std::vector<std::string> tablica(5, "text");
Since std::vector manages it's memory itself, you don't need to delete it anywhere.
If you don't want to use vector, you can alway use std::unique_ptr<std::string[]>. The only difference in you code would be to send tablica.get() to your functions, and use std::make_unique<std::string[]>(rozmiar) instead of new std::string[rozmiar]
The correct answer is use std::vector. For example:
vector<string> startowa(int& rozmiar)
{
rozmiar = 5;
vector<string> tablica(rozmiar);
for (int i = 0; i < rozmiar; i++)
tablica[i] = "text";
return tablica;
}
Note the return by value. Don't fall into the trap of thinking you're saving processing time by returning by reference. That vector goes out of scope and is destroyed at the end of the function. With a returned reference the best you can hope for is the caller receiving a load of garbage and crashing before any damage can be done.
A decent compiler will eliminate the copying when you return the vector by value, and if the compiler decides that it cannot, std::move will take care of that.
vector also knows how big it is, eliminating the need for rozmiar.
Now... What went wrong? Let's look at the code
int main()
{
int wybor = 1, rozmiar = 1;
string * tablica = startowa(rozmiar);
startowa allocated an array of strings and stored a pointer to the array in tablica.
while (wybor != 55)
{
cin >> wybor;
if (wybor == 1)
{
rozmiar++;
tablica = plusx(tablica, rozmiar);
plusx allocated a new array of strings, a pointer to which has been returned and written over the pointer returned by startowa. startowa's array is now effectively lost, leaked, as it is next to impossible to find again to delete[].
We would need to delete[] tablica; before making the assignment. Clearly we can't do this before calling plusx as tablica is a parameter, so we need to store a temp.
string * temp = plusx(tablica, rozmiar);
delete[] tablica;
tablica = temp;
But what if something unexpected happens and an exception is thrown? The code never hits the delete[] and BOTH allocations are lost. vector handles all this for you.
And back to the code
}
if (wybor == 6)
wybor = 55;
else
{
rozmiar--;
tablica = minusx(tablica, rozmiar);
Same problem and solution as above.
}
// there were other "ifs" but its just a part of the code
}
for (int i = 0; i < rozmiar; i++)
cout << tablica[i] << endl;
delete[] tablica;
One of an in-determinant number of allocations is released here. The rest are lost.
cin >> wybor;
getchar();
return 0;
}
I am currently tackling this assignment for my computer science class:
Make your own dynamic array template. It should allow creating contiguous arrays (filled with things of the same type) which you can extend without worrying about running out of space.
Do one version using malloc and free.
Do one version using new and delete.
My version using new and delete works flawlessly; however, in trying to convert my new/delete code to using malloc/free, I keep getting a seg fault. I have narrowed down the segfault (I think), to being in a single function: addData. Take a look at the code in my main I used to test this:
Array2<int> *testArray3 = new Array2<int>(5);
Array2<int> *testArray4;
testArray3->initArray();
testArray3->printArray();
testArray4 = testArray3->addData(7);
testArray4->printArray();
return 0;
This gives a seg fault; however, when I change it to this:
Array2<int> *testArray3 = new Array2<int>(5);
Array2<int> *testArray4;
testArray3->initArray();
testArray3->printArray();
testArray4 = testArray3; //->addData(7);
testArray4->printArray();
return 0;
There is no seg fault. This makes me believe the issue is in my addData function. Here is the code for that:
Array2<T> *addData(T dataToAdd){
Array2 <T> *tmp;
tmp->data = this->getData();
Array2 <T> *newData;
newData->data = (T *) malloc(sizeof(T)*(this->size + 1));
for (int i = 0; i < tmp->getSize() + 1; ++i){
if (i < tmp->getSize()){
//newData->data[i] = tmp->data[i];
newData->setData(tmp->getData()[i], i);
}
else{
//newData->data[i] = dataToAdd;
newData->setData(dataToAdd, i);
}
}
free(tmp->data);
free(this->data);
return newData;
};
I am new to programming as a whole and have not completely wrapped my head around pointers and memory allocation, etc. Any advice you could give me would be greatly appreciated! In case you need to see the rest of the code, here is the entire file I coded my template in. Thank you so much for your time!
#include <iostream>
#include <string>
#include <cstdlib>
#include <sstream>
using namespace std;
template<typename T>
class Array2{
public:
Array2(int size){
this->size = size;
data = (T *) malloc(sizeof(T)*size);
};
Array2<T> *addData(T dataToAdd){
Array2 <T> *tmp;
tmp->data = this->getData();
Array2 <T> *newData;
newData->data = (T *) malloc(sizeof(T)*(this->size + 1));
for (int i = 0; i < tmp->getSize() + 1; ++i){
if (i < tmp->getSize()){
//newData->data[i] = tmp->data[i];
newData->setData(tmp->getData()[i], i);
}
else{
//newData->data[i] = dataToAdd;
newData->setData(dataToAdd, i);
}
}
free(tmp->data);
free(this->data);
return newData;
};
~Array2(){
free(this->data);
};
void initArray(){
for (int i = 0; i < this->size; ++i){
//this->data[i] = i;
this->setData(i, i);
}
};
void printArray(){
//ostringstream oss;
string answer = "";
for (int i = 0; i < this->size; ++i){
//oss << this->data[i] + " ";
cout << this->data[i] << " ";
}
//answer = oss.str();
cout << answer << endl;
};
T* getData(){
return this->data;
}
int getSize(){
return this->size;
}
void setData(T data, int index){
this->getData()[index] = data;
}
private:
int size;
T* data;
};
Array2 <T> *tmp;
Allocates a pointer. This does not point the pointer at anything or allocate any storage for the pointer to point at. What it points at without being explicitly assigned is undefined. If you are lucky, and you are this time, tmp points at an invalid location and the program crashes. If you are unlucky, tmp points at some usable region of program memory and lets you write over it, destroying whatever information was there.
tmp->data = this->getData();
Attempts to access the data member at tmp, but fortunately for you the access is in invalid memory and the program comes to a halt. It also has tmp's data pointing at this's data, and that's a dangerous position to be in. Changes to one will happen to the other because they both use the same storage. Also think about what will happen to this->data if you free tmp->data.
Or perhaps I'm wrong and the halt is here for the same reason:
Array2 <T> *newData;
newData->data = (T *) malloc(sizeof(T)*(this->size + 1));
Both need to be fixed. tmp doesn't have to live long, so we can make it a temporary local variable.
Array2 <T> tmp;
Typically this will be created on the stack and destroyed when the function ends and tmp goes out of scope.
But this will not work because Array2's constructor requires a size so it can allocate the array's storage. You need to find out how big to make it. Probably something along the lines of:
Array2 <T> tmp(this->size + 1);
But frankly I don't think you need tmp at all. You should be able to copy the dataToAdd directly into newData without using tmp as an intermediary.
newData is eventually going to be returned to the caller, so it needs a longer scope. Time to use new.
Array2 <T> *newData = new Array2 <T>(this->size + 1);
And through the magic of the constructor... Wait a sec. Can't use new. That makes this hard. malloc doesn't call constructors, so while malloc will allocate resources for newData, it doesn't do the grunt work to set newData up properly. Rule of thumb is Never malloc An Object. There will be exceptions I'm sure, but you shouldn't be asked for this. I recommend using new here and politely telling the instructor they are on crack if they complain.
Anyway, new Array2 <T>(this->size + 1) will allocate the data storage for you with it's constructor.
There is an easier way to do this next bit
for (int i = 0; i < tmp->getSize() + 1; ++i){
if (i < tmp->getSize()){
//newData->data[i] = tmp->data[i];
newData->setData(tmp->getData()[i], i);
}
else{
//newData->data[i] = dataToAdd;
newData->setData(dataToAdd, i);
}
}
Try:
for (int i = 0; i < tmp->size; ++i){
newData->data[i] = tmp->data[i]; // you were right here
}
newData->data[tmp->size] = dataToAdd;
And back to something I hinted at earlier:
free(tmp->data);
free(this->data);
Both tmp->data and this->data point to the same memory. To be honest I'm not sure what happens if you free the same memory twice, but I doubt it's good. Regardless, I don't think you want to free it. That would leave this in a broken state.
Recap and fixes
Array2<T> *addData(T dataToAdd)
{
Array2 <T> *newData = new Array2 <T>(this->size + 1);
for (int i = 0; i < this->size; ++i)
{
newData->data[i] = this->data[i];
}
newData->data[this->size] = dataToAdd;
return newData;
};
This version leaves this intact and returns a newData that is one bigger than this. What it doesn't do is add anything to this. Which is goofy for a method named addData.
It also leads to stuff like this:
mydata = myData->addData(data);
which leaks memory. The original mydata is lost without deletion, resulting in a memory leak.
What I think you really need is a lot simpler:
Array2<T> & addData(T dataToAdd)
{
this->data = realloc(this->data, this->size + 1);
this->data[this->size] = dataToAdd;
this->size++;
return *this;
};
realloc effectively allocates a new buffer, copies the old buffer into the new one, and frees the old buffer all in one fell swoop. Groovy.
We then add the new element and increment the count of elements stored.
Finally we return a reference to the object so it can be used in a chain.
Usage can be
myData.addData(data);
myData.addData(data).addData(moredata);
myData.addData(data).printArray();
and if you have operator << support written
std::cout << myData.addData(data) << std::endl;
I'd go back over the new version of Array if I were you. Most of the bugs picked off here are conceptual errors and also apply to it. You might just be getting unlucky and it merely looks like it works. I just read C++ Calling Template Function Error. The posted solutions fixed the immediate problem, but did not touch the underlying memory management problems.
As for the rest of your class, I advice following the link and answering What is The Rule of Three? Because Array2 violates the heck out of it.
I'm having an issue with a lot of memory leaks from a class I've created. The assignment is requires creating a word search puzzle on the heap. I've created my destructor, copy constructor and overload the assignment operator.
I think there must be something wrong with one of these functions, because the final check to ensure it is working is to create objects in a loop, to see if it fails and my function is crashing. I've tried different forms of the destructor and I've tried changing around the copy and assignment operator with no luck. Kind of at a loss, and the lack of warnings is really making it difficult to debug without a proper understanding of the heap.
Any help would be really appreciated!
Here are some functions that are working with the heap.
JumblePuzzle::~JumblePuzzle(){
for (int i = 0; i < size; ++i){
delete jumble[i];
}
delete jumble;
}
JumblePuzzle::JumblePuzzle(string word, string diff){
int i = 0;
toHide = word;
difficulty = diff;
jumble = buildArray();
fillArray();
hideWord();
}
JumblePuzzle::JumblePuzzle(JumblePuzzle& temp){
size = temp.size;
rowPos = temp.rowPos;
colPos = temp.colPos;
direction = temp.direction;
toHide = temp.toHide;
difficulty = temp.difficulty;
jumble = temp.getJumble();
}
JumblePuzzle& JumblePuzzle::operator=(const JumblePuzzle& right){
if (this != &right){
for (int i = 0; i < size; ++i){
delete jumble[i];
}
delete[] jumble;
size = right.size;
rowPos = right.rowPos;
colPos = right.colPos;
direction = right.direction;
toHide = right.toHide;
difficulty = right.difficulty;
jumble = right.getJumble();
}
return *this;
}
charArrayPtr* JumblePuzzle::buildArray() const{
charArrayPtr* array = new char*[size];
for (int i = 0; i < size; ++i){
array[i] = new char[size];
}
return array;
}
Here's the line its failing on.
int loopLimit =20;
for (int i = 0; i < loopLimit; i++)
JumblePuzzle jp("HIDDENWORD", "hard");
Thanks for any possible help!
EDIT:
Here is my .h file as well.
#ifndef JUMBLE_H_
#define JUMBLE_H_
#include <time.h>
#include <cstdlib>
#include <string>
using namespace std;
typedef char* charArrayPtr;
class BadJumbleException {
public:
BadJumbleException(const string&);
string& what();
private:
string message;
};
class JumblePuzzle{
public:
JumblePuzzle(string, string); //simple constructor
JumblePuzzle(JumblePuzzle&); //copy constructor
~JumblePuzzle(); //deconstructor
charArrayPtr* getJumble() const;
JumblePuzzle& operator=(const JumblePuzzle&);
//accessors
int getSize();
int getRowPos();
int getColPos();
char getDirection();
private:
//attributes
int size;
int rowPos;
int colPos;
char direction;
charArrayPtr* jumble;
string toHide;
string difficulty;
void fillArray();
void hideWord();
char randomDirection();
int randomNum(int);
charArrayPtr* buildArray() const;
};
#endif
and my getJumble. It's used to get the actual word search created. Returned a copy rather than the pointer so it cant be modified.
charArrayPtr* JumblePuzzle::getJumble() const{
charArrayPtr* tempJumble = new char*[size];
for (int i = 0; i < size; ++i){
tempJumble[i] = new char[size];
}
for (int i = 0; i < size; i++){
for (int j = 0; j < size; j++){
tempJumble[i][j] = jumble[i][j];
}
}
return tempJumble;
}
There is one major thing wrong with your code, and that is you failed to initialize the "size" member in the JumblePuzzle(string, string) constructor.
There are other things you should do:
1) Create a separate function to destroy the 2d array within the JumblePuzzle class. You seem to be copying the same loops to do this in multiple places. No need for that if you just call a function to do this work.
2) Your assignment and copy constructor are not exception safe. If new[] throws an exception during the creation of the copy, then the original object has invalidated data. In other words, you've destroyed the data, and when you want to create another 2d array, when new[] says "oops", you've destroyed your original data and can't get it back.
Here's my code:
template<class T> class Test
{
public:
int Size = 0;
int Length = 0;
T* Items;
Test() {}
~Test()
{
delete [] Items;
}
void Append(const T& newItem)
{
if (Size + 1 >= Length)
{
Length += 250;
T* old = Items;
Items = new T[Length + 250];
for (int i = 0; i < Size; i++)
Items[i] = old[i];
delete [] old;
}
Items[Size] = newItem;
Size++;
}
};
Test<int> test;
for (int i = 0; i < 500000; i++)
test.Append(i);
I'm populating the dynamic array with 500000 integers which must take just 1-2Mb but it takes about 30Mb. There's no problem if i set the initial size to 500000(i.e. no resizing occurring). The grow value(250) seems to affect the memory somehow, if it's larger(for example 1000) then the memory usage is pretty low. What's wrong?
Typically, when you are reallocating an array, you do not want to modify the actual array until the very last second (to maintain exception safety):
T* temp = new T[new_size];
// assume count is the previous size and count < new_size
std::copy(Items, Items + count, temp);
std::swap(temp, Items);
delete [] temp;
Aside from that, there is nothing visible in your code that would cause a memory leak.
The extra size can possibly be due to other optimizations (being turned off) and/or debugging symbols being turned on. What compiler options are you using (and what compiler)? It should be noted that extra size is not necessarily an indication of a memory leak. Have you run this in a debugger or memory profiler which found a leak?
It should also be noted that std::vector does all of this for you.
Looking at your code, you're going to segfault more so than leak memory due to the fact that calling delete or delete[] on a non-NULL, but previously deallocated, pointer is a Bad Thing. Also, I don't believe this is your real code, because what you posted won't compile.
When you delete a pointer, always set it to NULL afterwards. It's good practice to initialize to NULL as well. Let's fix up your code to make sure we don't call delete on previously deallocated pointers. Also, let's initialize our pointer to NULL.
Your misuse of memory probably stems from the following lines of code:
Length += 250;
T* old = Items;
Items = new T[Length + 250];
Notice that you increment Length by 250, but then allocate Length+250 more elements? Let's fix that, too.
template<class T>
class Test
{
public:
int Size;
int Length;
T* Items;
Test() : Size(0), Length(0), Items(NULL){}
~Test() {
if (Items != NULL)
delete [] Items;
}
void Append(const T& newItem)
{
if (Size + 1 >= Length)
{
Length += 250;
T* old = Items;
Items = new T[Length];
for (int i = 0; i < Size; i++)
Items[i] = old[i];
delete [] old;
old = NULL;
}
Items[Size] = newItem;
Size++;
}
};
int main(){
Test<int> test;
for (int i = 0; i < 500000; i++)
test.Append(i);
}