I am writing code for a backtracking approach to a Traveling Salesman type of problem. So at each point i will recurse for rest of the un-visited points.
I could not use any library/functions other than cout, cin, new and delete (so no vector). So for the problem i want to keep a track of what all points i have visited till now. I am using a dynamic boolean array for this. So i want to pass the dynamic array to a function as value to keep track of this.
This is what i have tried till now.
I tried to wrap the array in a struct, but the memory dealocation (delete) is giving error (Segmentation fault)
typedef struct Barray{
bool* a;
int size;
Barray(int size) { a = new bool[size]; this->size = size; }
Barray(const Barray& in) {
if(a) delete[] a; // error
a = new bool[in.size];
this->size = in.size;
for (int i = 0; i < in.size; i++)
a[i] = in.a[i];
}
~Barray() { delete[] a; } // error
}barray;
This is my recursive function call
void find_mindist(barray visited, int dist_now, int cur_p) {
if (base condition)
{return ;}
for (int i = 0; i < n; i++) {
if (visited.a[i]) continue;
barray tdist = visited;
tdist.a[i] = true;
int ndist = dist_now + dist(points[cur_p], points[i]);
find_mindist(tdist, ndist, i);
}
return ;
}
So my questions are -
how can i pass a dynamic array to a function as value?
Why is the delete above giving error?
First of all, the recommended approach for a local visited information is not the endless copying of the whole visited collection, but a mark->recurse->unmark approach. So whatever you do, please keep a single boolean array for the visited information and update its content to your needs.
The other problems occur because you try to delete an uninitialized pointer in the copy constructor. Also, the assignment operator should be overloaded as well to avoid unpleasent surprises. But non of this really matters if you don't copy your visited information anymore.
The problem this is a copy constructor. As such, on entry, a is uninitialized (so contains garbage), so the delete is invalid.
Barray(const Barray& in) {
if(a) delete[] a; // error
a = new bool[in.size];
this->size = in.size;
for (int i = 0; i < in.size; i++)
a[i] = in.a[i];
}
Just remove the delete line. Also, prefer to initialize members, rather
than assign them, so:
Barray(const Barray& in)
: a(new bool[in.size])
, size(in.size) {
for (int i = 0; i < in.size; i++)
a[i] = in.a[i];
}
Also, remember the Rule of Three. You need an copy assignment operator. The simplest is:
Barry& operator=(const Barray& in) = delete;
which just forces a compilation error if you try to use it! Better is:
Barry& operator=(const Barray in) { // **NOTE** pass by value!
std::swap(this.a, in.a);
std::swap(this.size, in.size);
}
This version provides the strong exception guarantee. You aren't allowed to use std::swap, so you'll either have to write your own, or write it out by hand (you choose).
Finally, if you ever find yourself returning a Barray, you should write a move constructor:
Barray(Barray &&in)
: a(in.a)
, size(in.size) {
in.a = nullptr;
}
This can save a lot of copying!
Related
I have to write a code that gets a string and turns it into an object of a class. Everything is working as expected but I'm unable to deallocate the dynamically allocated 2d array of objects.
I know the issue is within the destructor and the Move assignment operator for the object, I keep getting SIGBRT and EXC_BAD_ACCESS errors when I try to run it.
Below is my Code for the constructor, destructor and move assignment/constructor
//CustomerOrder.cpp
CustomerOrder::CustomerOrder(std::string&
src):Name(src),Product(),ItemCount(),ItemList(),field_width(){
std::vector<ItemInfo> info;
std::string* tokens[] = { &Name, &Product };
Utilities utils;
size_t next_pos = -1;
bool more = true;
for (auto& i : tokens) {
if (!more) break;
*i = utils.extractToken(src, next_pos, more);
}
while (more){
info.push_back(utils.extractToken(src, next_pos, more));
}
if(!info.empty() && info.back().ItemName.empty()){
info.pop_back();
}
ItemCount = info.size();
ItemList = new ItemInfo*[ItemCount];
for (int i = 0; i < ItemCount; i++){
ItemList[i] = new ItemInfo(info.at(i).ItemName);
}
if (utils.getFieldWidth() > field_width){
field_width = utils.getFieldWidth();
}
}
CustomerOrder::~CustomerOrder(){
for(int i = 0; i<ItemCount;i++){
delete[] ItemList[i];
}
delete[] ItemList;
}
CustomerOrder::CustomerOrder(CustomerOrder&& src){
*this = std::move(src);
}
CustomerOrder& CustomerOrder::operator=(CustomerOrder&& src){
if(this!= &src){
delete [] ItemList;
Name = std::move(src.Name);
Product = std::move(src.Product);
ItemCount = std::move(src.ItemCount);
ItemList = std::move(src.ItemList);
src.ItemList = nullptr;
}
return *this;
}
And the ItemInfo struct
//ItemInfo struct
struct ItemInfo
{
std::string ItemName;
unsigned int SerialNumber;
bool FillState;
ItemInfo(std::string src) : ItemName(src), SerialNumber(0),
FillState(false) {};
};
You are combining "new" with "delete[]". If you use "new" use "delete" if you use "new[]" then use "delete[]" for the thing.
This is your problem there: "delete[] ItemList[i];" it should be "delete ItemList[i];" instead
This line of your code ItemList[i] = new ItemInfo(info.at(i).ItemName); doesn't allocate a dynamic array, yet this code in your destructor tries to delete it as thought it was a dynamic array.
for(int i = 0; i<ItemCount;i++){
delete[] ItemList[i];
}
A quick fix would to be to change delete[] to delete. However, it appears as though it would be much easier to simply allocate a single dynamic array. In other words, allocate ItemList as such ItemList = new ItemInfo[ItemCount]; Granted, you would have to change the type, but it makes more sense from what you posted.
Another possible issue is that in your destructor you don't check if the ItemList is a nullptr or actually allocated to anything. To which, your destructor could possibly try to access invalid data. Not only that, but your move operator deletes the ItemList without deleting the data inside of it.
You could make a function to free up the data in ItemList and then call that function from the destructor and move operator.
On a side note, why are you using dynamic 2D arrays when it appears that you know how to use vectors? A vector would handle all of this in a much simpler fashion. For example, the type would be std::vector<std::vector<ItemInfo>>.
I have a class representing an array, holding pointers to my other class objects.
#include "Edge.h"
class Array
{
private:
Edge** _headPtr;
int arraySize;
public:
Array(int);
void pushBack(Edge*);
// other functions...
};
Array::Array(int arraySize)
{
this->arraySize = arraySize;
this->_headPtr = new Edge*[arraySize];
}
Program always returns memory allocation errors after calling
// inserts an element on the end of the array
void Array::pushBack(Edge* element)
{
if (arraySize == 0) {
_headPtr = new Edge*[1];
_headPtr[0] = element;
arraySize++;
}
else {
Edge** _tempPtr = new Edge*[arraySize + 1]; // crashing here
memcpy(_tempPtr, _headPtr, arraySize * sizeof(Edge*));
//for (int i = 0; i < arraySize; i++) delete _headPtr[i];
delete[] _headPtr;
_tempPtr[arraySize] = element;
_headPtr = _tempPtr;
arraySize++;
}
}
I have commented out the for (int i = 0; i < arraySize; i++) delete _headPtr[i];
part because it was causing _free_dbg(block, _UNKNOWN_BLOCK); error.
From what I've found in other questions here I guess there must be a flaw in my understanding of dynamic array of pointers to class objects, but after spending much time trying to fix this I've run out of ideas.
The general idea of my program is to perform time efficiency measurements for some graph algorithms, this being part of Prim's algorithm implementation.
Call stack leading to this situation looks like this:
BinaryHeap queue = BinaryHeap();
queue.addNewElement(new Edge(v, v2, edgeWeight));
which looks like this
void BinaryHeap::addNewElement(Edge* element)
{
heapElements->pushBack(element);
heapFix_UP(heapElements->getSize()-1);
}
And finally pushBack method.
heapElements is Array* heapElements inside the BinaryHeap class, initialized with
heapElements = new Array(); in BinaryHeap constructor.
Edge is a very simple class holding only three integer values.
Please do not suggest using std::vector, the whole idea is not to use STL.
OK, I have found the solution. All of the code above works good, the bug was in a completely different place in my code.
What was so wrong that it was causing the whole program to crash many lines later?
This:
int** graphMatrix;
graphMatrix = new int*[vertex];
for (i = 0; i < edges; i++) graphMatrix[i] = new int[edges];
So simple, yet so harmful.
It is a part of my incidence matrix implementation. Now the reason for all crashes is pretty obvious - trying to write/read unallocated memory and causing heap corruptions.
This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 8 years ago.
I have problem with the following class. I think the problem is with string array, cause I made two other classes and the problem was the same. When I run the program it throws "double free or corruption", but I do not think any double corruption is possible. The problem is same with input string as reference or as common argument in Add method.
class WareH
{
public:
WareH(void)
{
first = true;
rows = 1;
inLine = 0;
cnt = 0;
max = 2;
cL = 0;
strs = new string[max];
}
~WareH(void)
{
delete [] strs;
}
bool Add(string& str, int ending)
{
if (first)
inLine++;
else
cL++;
if (ending == 0)
{
if (first)
first = false;
if (cL != inLine)
return false;
rows++;
}
strs[cnt++] = str;
Bigger();
return true;
}
void Bigger(void)
{
if(max == cnt)
{
max *= 2;
string* tmp = new string[max];
for (int i = 0; i < cnt; i++)
tmp[i] = strs[i];
delete [] strs;
strs = tmp;
}
}
friend ofstream& operator<<(ofstream& of,WareH war)
{
for (int a = 0; a < war.cnt; a++)
of << war.strs[a] << endl;
return of;
}
private:
bool first;
int rows, inLine, cnt, max, cL;
string* strs;
};
When a class manages resources, and releases them in its destructor, you must consider the Rule of Three to make sure that copying an object will not result in two objects managing the same resource.
That is what is happening here: the default copy constructor and copy-assignment operator will copy the pointer, giving you two objects which will both try to delete the same array on destruction. Solutions are:
Delete the copy constructor and copy-assignment operator to prevent copying; or
Implement them to copy the strings into a new array, not just the pointer; or
Use std::vector rather than messing around managing memory allocation yourself.
When I run the program it throws "double free or corruption", but I do not think any double corruption is possible.
Educated guess here:
The problem is not in the code you've shown, but in the client code. Here's what I think happens:
you wrote client code that instantiates (or assigns or returns by value or stores in a std container) WareH instances, and since you do not define a copy constructor and assignment operator (see "The Big Three"), they end up copying the values from your source objects. When the first of these instances (that are assigned to each other) are deleted, they delete the strs pointer.
When the second instance is deleted, they delete the same strs pointers that were deleted before (because the default copy constructors and assignment operators do not duplicate the allocated memory but just copy the pointers).
Solutions (if that is indeed, the problem):
working (and bad) solution: explicitly define copy construction and assignment operator for your class.
working (and good) solution: implement your strs as a std::vector<std::string> instead of std::string* and cnt.
I'm having trouble with memory usage in my homework program, which is used to store information about companies and its' owners. Class СompanyTemplate represents this info.
public:
CompanyTemplate (const string & oName,
const string & oAddr,
const string & cName,
const string & cAddr);
Another Class CCompanyIndex is used to store multiple records using a dynamical array of pointers (I'm not allowed to use vectors). Here's CCompanyIndex constructor:
CCompanyIndex :: CCompanyIndex (void)
{
allocated = 1000;
current_size = 0;
pole = new CompanyTemplate* [allocated];
for (int i=0; i<allocated; i++)
{
pole[i] = NULL;
}
}
CCompanyIndex also provides methods Add (add record), Del (delete record), Search(search an information about owner's company.
I'm having trouble with the Add method, although all basic tests are good, I have memory leaks, as valgrind says, in Add method.
bool CCompanyIndex :: Add( const string & oName,
const string & oAddr,
const string & cName,
const string & cAddr )
{
int pos = findPos(oName, oAddr);
if(pos != -1)
{
return false;
}
if ((current_size)>=allocated)
{
CompanyTemplate ** temp;
allocated = allocated*2+1;
temp = new CompanyTemplate* [allocated];
for (int i=0; i<current_size; i++)
{
temp[i]=pole[i];
}
pole = temp;
for (int i=0; i<current_size; i++ )
{
if ((pole[i])->Compare(oName,oAddr)<0)
{
current_size++;
for (int k=current_size-1; k>=i; k--)
{
pole[i] = new Comp pole[k+1]=pole[k];
}anyTemplate(oName, oAddr, cName,cAddr);
return true;
}
}
pole[current_size] = new CompanyTemplate(oName, oAddr, cName,cAddr);
current_size++;
return true;
}
Array elements reallocating works as expected, more likely I have an error in destructor, but still can't find.
Here it is:
CCompanyIndex :: ~CCompanyIndex (void)
{
for (int i=0; i<allocated; i++)
{
delete pole[i];
}
delete [] pole;
pole = NULL;
}
Thanks
if ownership is unclear, just use std::shared_ptr.
of course in a professional setting a better answer might be to analyze better and get a better idea of ownership, like, is it really shared?
but absent that, use a std::shared_ptr.
by the way, it looks like your class fails to handle copying properly. this is called the "rule of three" (or for c++11, the "rule of five"). essentially, if you define either of destructor, copy constructor or copy assignment operator, then you most likely need all three in order to deal properly with copying.
but the simplest is to not define such operations but instead use standard library containers, like std::vector, and standard library smart pointers, like std::shared_ptr.
e.g. instead of defining pole as a raw pointer (to array), define it as a std::vector.
With such a general title, the general answer will: use a vector of shared_ptr.
But I assumed that your homework is to implement a kind of std::vector<CompanyTemplate> using "low" level C++, witout STL and smart pointers (with otherwise is the best way of using c++). So:
Maybe you have other error, but here are two:
CompanyTemplate ** temp;
allocated = allocated*2+1;
temp = new CompanyTemplate* [allocated];
int i=0
for (; i<current_size; i++)
{
temp[i]=pole[i];
}
for (; i<allocated ; i++) // you want to make NULL the new pointers
{
temp[i]=NULL
}
delete [] pole; // delete old array.
pole=temp;
Suppose we have the following:
class StringClass
{
public:
...
void someProcessing( );
...
StringClass& operator=(const StringClass& rtSide);
...
private:
char *a;//Dynamic array for characters in the string
int capacity;//size of dynamic array a
int length;//Number of characters in a
};
StringClass& StringClass::operator=(const StringClass& rtSide)
{
capacity = rtSide.capacity;
length = rtSide.length;
delete [] a;
a = new char[capacity];
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i];
return *this;
}
My question is: why does this implementation of overloading the assignment operator cause problems when we try to assign an object to itself like:
StringClass s;
s = s;
The textbook I'm reading (Absolute C++) says that after delete [] a; "The pointer s.a is then undefined. The assignment operator has corrupted the object s and this run of the program is probably ruined."
Why has the operator corrupted s? If we're reinitalizing s.a right after we delete it, why does this cause such a problem in the program that we have to redefine the function as:
StringClass& StringClass::operator=(const StringClass& rtSide)
{
if (this == &rtSide)
//if the right side is the same as the left side
{
return *this;
}
else
{
capacity = rtSide.capacity;
length = rtSide.length;
delete [] a;
a = new char[capacity];
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i];
return *this;
}
}
If you are assigning an object to itself both a and rt.a point to the same string, so when you do delete [] a you are deleting both what a and rt.a point to; then you do reallocate it, but the data you were going to copy (on itself) in the loop has been lost in the delete.
In the loop now you will just copy whatever junk happens to be in the memory returned by new on itself.
By the way, even with the "safety net" of the self-assignment check that assignment operator isn't completely ok (for instance, it's not exception safe); the "safe" way to define the "big three" (copy constructor, assignment operator, destructor) is using the "copy and swap idiom".
If you self-assign, you free (delete) the string via the LHS argument before you copy it to the newly allocated space via the RHS argument. This is not a recipe for happiness; it is undefined behaviour and anything may happen. A crash is plausible; if you're really unlucky, it may appear to work.
Consider what the value of rtSide.a is when you're inside the broken operator=.
It's the same as this->a, the values you just clobbered. Accessing non-owned memory is undefined behavior, thus accessing this->a is undefined behavior (since you just freed it).
delete [] a;
a = new char[capacity];
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i]; //Invalid when this->a == rtSide.a
//because rtSide.a is no longer owned by your program.
If you did actually want to do this, you would have to make a copy of a before deleting it:
char* ca;
if (this == &rtSide) {
ca = copy of rtSide.a or this->a;
} else {
ca = rtSide.a;
}
//Do your assigning and whatnot
if (this == &rtSide) {
delete[] ca;
}
Obviously it's much more efficient to just do nothing instead of making temporary copies of all of an instances own members. It's the same concept as doing int x = 5; int y = x; x = y;
It is because you've first deleted the pointer delete [] a;
and then later on trying to copy from the deleted location:
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i]; //rtSide has already been deleted as 'this' and '&rtSide' are same.
Remember it is the same location you are trying to copy from, which you've already deleted.
Hence, the error!
The later code you posted fixes this problem by checking for self-assignment as a separate case.
delete [] a;
a = new char[capacity];
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i];
That's why. Think of it like this:
You delete whatever a points to, then allocate a new chunk of memory. The new chunk of memory contains garbage which becomes your new data. Do not be confused by the loop that does a[i] = rtSide.a[i]; that only copies the garbage onto itself.
Remember, this and rtSide both lead you to the same object. When you modify the object using this the object that rtSide refers to is modified.