Heap Leak in a cpp code - c++

I am doing a project named wireless Network Toplogy. It use graphs as a data structure. I have make pointers but am facing heap leak problems. Please can anyone help fix this error? Where to call the delete operator? The cpp code is attached:
#include <string>
#include <ctime>
#include <cstdlib>
#include <iostream>
#include "myGraph.h"
#include "wirelessNetwork.h"
using namespace std;
void main()
{
srand(time(NULL));
/* First part of the experiments */
for (int i = 500; i <= 950; i += 50)
{
wirelessNetwork *g = new wirelessNetwork(10, i);
std::cout << (L"For network with n=") << i << (L": ") << std::endl;
double average = (static_cast<double>(g->graph->numEdges) / (static_cast<double>(g->graph->numVertices)));
std::cout << (L" The average degree is ") << average << std::endl;
std::cout << (L" The maximum degree is ") << g->getMaxDegree() << std::endl;
/* Perform topology control */
g->topologyControl();
std::cout << (L" After topology control: ") << std::endl;
average = (static_cast<double>(g->graph->numEdges)) / (static_cast<double>(g->graph->numVertices));
std::cout << (L" The average degree is ") << average << std::endl;
std::cout << (L" The maximum degree is ") << g->getMaxDegree() << std::endl;
std::cout << std::endl;
}
/* Second part of the experiments */
wirelessNetwork *g = new wirelessNetwork(10, 1000);
std::cout << (L"***********************************") << std::endl;
for (int i = 1; i <= 10; i++)
{
/* Randomly pick two vertices as the source and destination */
int i1 = static_cast<int>(1000 * rand());
int i2 = static_cast<int>(1000 * rand());
string nameTemp = "a";
string node1 = nameTemp + std::to_string(i1);
string node2 = nameTemp + std::to_string(i2);
//ORIGINAL LINE: String[] route = g.compassRouting(node1, node2);
string *route = g->compassRouting(node1, node2);
std::cout << std::endl;
std::cout << (L"Path generated from ") << node1 << (L" to ") << node2 << (L":") << std::endl;
for (int k = 0; k < route->length(); k++)
{
std::cout << (L" ") << route[k];
}
if (node2 != route[route->length() - 1])
{
std::cout << std::endl;
std::cout << (L" No route found...") << std::endl;
}
std::cout << std::endl;
std::cout << (L" Length of the path generated is ") << (route->length() - 1) << std::endl;
}
/* Third part of the experiments */
g->topologyControl();
std::cout << std::endl;
std::cout << (L"***********************************") << std::endl;
std::cout << (L"After topology control...") << std::endl;
for (int i = 1; i <= 10; i++)
{
int i1 = static_cast<int>(1000 * rand());
int i2 = static_cast<int>(1000 * rand());
string nameTemp = "a";
string node1 = nameTemp + std::to_string(i1);
string node2 = nameTemp + std::to_string(i2);
//ORIGINAL LINE: String[] route = g.compassRouting(node1, node2);
string *route = g->compassRouting(node1, node2);
std::cout << std::endl;
std::cout << (L"Path generated from ") << node1 << (L" to ") << node2 << (L":") << std::endl;
for (int k = 0; k < route->length(); k++)
{
std::cout << (L" ") << route[k];
}
if (node2 != route[route->length() - 1])
{
std::cout << std::endl;
std::cout << (L" No route found...");
}
std::cout << std::endl;
std::cout << (L" Length of the path is ") << (route->length() - 1) << std::endl;
}
}
`

One way of identifying when to call delete operator is to check when that pointer variable goes out of scope and to delete it just before it goes out of scope.
void func()
{
ClassA* ptr1 = new ClassA;
//do NULL check for ptr1 and do stuff
delete ptr1;
//here ptr1 will lose scope.
//If not deleted, it will become a memory leak.
}
There can be scenarios where we cannot delete a pointer even if it goes out of scope. For example if we store the new pointer value in some other pointer variable, and the 2nd variable is still not out of scope.
void func(bool IsReady)
{
ClassA* ptr1 = NULL;
if(IsReady)
{
ClassA* ptr2 = new ClassA;
//do stuff
ptr1 = ptr2;
//in this case, even though ptr2 will lose scope outside this block,
//the ptr2 value is assigned to ptr1 which is does not lose scope outside this block.
}
//here ptr1 will still contain the data we copied in the if block,
//else it will be NULL. After use of ptr1 is complete, do a NULL check and delete.
if(ptr1 != NULL)
delete ptr1;
}
In your case I see only the first type, and only 2 places the new operator is called.
Have called the delete operator at the appropriate place for the first case, just before g goes out of scope:
/* First part of the experiments */
for (int i = 500; i <= 950; i += 50)
{
wirelessNetwork *g = new wirelessNetwork(10, i);
std::cout << (L"For network with n=") << i << (L": ") << std::endl;
double average = (static_cast<double>(g->graph->numEdges) / (static_cast<double>(g->graph->numVertices)));
std::cout << (L" The average degree is ") << average << std::endl;
std::cout << (L" The maximum degree is ") << g->getMaxDegree() << std::endl;
/* Perform topology control */
g->topologyControl();
std::cout << (L" After topology control: ") << std::endl;
average = (static_cast<double>(g->graph->numEdges)) / (static_cast<double>(g->graph->numVertices));
std::cout << (L" The average degree is ") << average << std::endl;
std::cout << (L" The maximum degree is ") << g->getMaxDegree() << std::endl;
std::cout << std::endl;
//here g loses scope and does not seem to be stored in any other pointer
delete g;
}
For the second case, call delete at the end of the function.
Hope this solves your issue of when to call the delete in your code.
However, you can avoid calling both new and delete in your case by replacing:
wirelessNetwork *g = new wirelessNetwork(10, i);
with
wirelessNetwork g(10, i);
And for accessing the member variables use g. instead of g->.
For example: g->topologyControl(); should be g.topologyControl();
Hope this answer helps.

The best answer is you shouldn't be using pointers or the new operator. As others suggested, just construct the object directly in the scope where it is needed, so it will be destroyed automatically when it goes out of scope.
A very common (but I think very poor) answer to this question, is to delete the object immediately before the pointer goes out of scope and/or put all your delete operations at the same nesting level as the corresponding new operations. As in this case, when that approach is practical, you almost always didn't need the pointer or the new at all. When it is not practical for the lifetime of the object to match the scope in which it is created, then you really need a pointer and use of the new operator and managing the lifetime of the object is one of the harder aspects of C++ programming. There are no generic answers in those cases. But until you have such a problem, don't create it by pointless use of the new operator.

Related

C++ accessing class array pointer in a pointer to a structure

I am new to C++ and I really need some help on this. I am trying to create a structure to interface with the GSL Monte-Carlo algorithms (a fact that is really not important for this example). I have searched all of the C++ tutorials, the stackoverflow posts and the GSL documentation with no luck. I am using the armadillo package for matrix manipulation; it is very robust. I am unable to use a dynamic array within the structure, as per the documentation, so I am trying to find a way to make my structure variable *M point to the values in my array *L[]. I am sure that this would be better with a vector but 1) the rest of the code (in bad form) uses pointers already, and 2) I am looking at this as a learning experience. I am surprised that the addresses for *M and *L[] are not the same in my code. I am also, less importantly, surprised that my std::cout prints a different number of spaces for each line. The code exits before printing the last std::cout as shown in the output below.
Thanks for your help!
#include "pch.h"
#include "stdio.h"
#include "complex"
#include "new"
#include "armadillo"
using namespace arma;
class Link
{
public:
arma::Mat<cx_double>::fixed<3, 3>* dir[4]; // pointer to directional SU(3) matrices
Link(); // default constructor
};
Link::Link() // default constructor - all directional matrices are the identity
{
for (size_t hcount = 0; hcount < 4; hcount++)
{
dir[hcount] = new arma::Mat<cx_double>::fixed<3, 3>{ fill::eye }; // create directional matrix in direction hcount
}
}
struct Param
{
Link* M;
};
int main()
{
const int size = 10;
Param* Parameters = new Param{ NULL };
Link* L[size];
arma::Mat<cx_double>::fixed<3, 3> One{ fill::eye };
for (size_t hcount = 0; hcount < 10; hcount++)
{
L[hcount] = new Link();
*L[hcount]->dir[1] = *L[hcount]->dir[1] + hcount * One; // Make each array element #1 unique
}
Parameters->M = L[0];
std::cout << "&L = " << &L << std::endl;
std::cout << "&Parameters->M = " << &Parameters->M << std::endl; // surprised that addresses are not the same
std::cout << std::endl;
std::cout << "&L[0] = " << &L[0] << std::endl;
std::cout << "&Parameters->M[0] = " << &Parameters->M[0] << std::endl;
std::cout << std::endl;
std::cout << "&L[5] = " << &L[5] << std::endl;
std::cout << "&Parameters->M[5] = " << &Parameters->M[5] << std::endl;
std::cout << std::endl;
std::cout << "&L[5]->dir[1] = " << &L[5]->dir[1] << std::endl;
std::cout << "&Parameters->M[5].dir[1] = " << &Parameters->M[5].dir[1] << std::endl;
std::cout << std::endl;
std::cout << "*L[5]->dir[1] = " << *L[5]->dir[1] << std::endl; // This works
std::cout << "*Parameters->M[5].dir[1] = " << *Parameters->M[5].dir[1] << std::endl; // This does not
std::cout << std::endl;
}
OUTPUT
&L = 0024F7CC
&Parameters->M = 004EEFD8
&L[0] = 0024F7CC
&Parameters->M[0] = 004E0578
&L[5] = 0024F7E0
&Parameters->M[5] = 004E05C8
&L[5]->dir[1] = 004E50C4
&Parameters->M[5].dir[1] = 004E05CC
*L[5]->dir[1] = (+6.000e+00,+0.000e+00) (0,0) (0,0)
(0,0) (+6.000e+00,+0.000e+00) (0,0)
(0,0) (0,0) (+6.000e+00,+0.000e+00)
*Parameters->M[5].dir[1] =
&L is the adress of L, so it's the adress of the pointer to the first element not the adress of the first elemenr itself. Same for & Parameters->M. That is the adress of thd the Member M from Parameters. You want to compare L[0] with Parameters->M except when M should not point to the element that L[0] refers to but to the start of the array itself, then you want to compare it with L. But then you also have to change the assignment.
I find it a bit weird that you use an array of pointers. Just use an array of Links.

Is it possible to have memory problems that don’t crash a program?

I wrote a text cipher program. It seems to works on text strings a few characters long but does not work on a longer ones. It gets the input text by reading from a text file. On longer text strings, it still runs without crashing, but it doesn’t seem to work properly.
Below I have isolated the code that performs that text scrambling. In case it is useful, I am running this in a virtual machine running Ubuntu 19.04. When running the code, enter in auto when prompted. I removed the rest of code so it wasn't too long.
#include <iostream>
#include <string>
#include <sstream>
#include <random>
#include <cmath>
#include <cctype>
#include <chrono>
#include <fstream>
#include <new>
bool run_cypher(char (&a)[27],char (&b)[27],char (&c)[11],char (&aa)[27],char (&bb)[27],char (&cc)[11]) {
//lowercase cypher, uppercase cypher, number cypher, lowercase original sequence, uppercase original sequence, number original sequence
std::ifstream out_buffer("text.txt",std::ios::in);
std::ofstream file_buffer("text_out.txt",std::ios::out);
//out_buffer.open();
out_buffer.seekg(0,out_buffer.end);
std::cout << "size of text: " << out_buffer.tellg() << std::endl;//debug
const int size = out_buffer.tellg();
std::cout << "size: " << size << std::endl;//debug
out_buffer.seekg(0,out_buffer.beg);
char *out_array = new char[size + 1];
std::cout << "size of out array: " << sizeof(out_array) << std::endl;//debug
for (int u = 0;u <= size;u = u + 1) {
out_array[u] = 0;
}
out_buffer.read(out_array,size);
out_buffer.close();
char original[size + 1];//debug
for (int bn = 0;bn <= size;bn = bn + 1) {//debug
original[bn] = out_array[bn];//debug
}//debug
for (int y = 0;y <= size - 1;y = y + 1) {
std::cout << "- - - - - - - -" << std::endl;
std::cout << "out_array[" << y << "]: " << out_array[y] << std::endl;//debug
int match;
int case_n; //0 = lowercase, 1 = uppercase
if (isalpha(out_array[y])) {
if (islower(out_array[y])) {
//std::cout << "out_array[" << y << "]: " << out_array[y] << std::endl;//debug
//int match;
for (int ab = 0;ab <= size - 1;ab = ab + 1) {
if (out_array[y] == aa[ab]) {
match = ab;
case_n = 0;
std::cout << "matched letter: " << aa[match] << std::endl;//debug
std::cout << "letter index: " << match << std::endl;//debug
std::cout << "case_n: " << case_n << std::endl;//debug
}
}
}
if (isupper(out_array[y])) {
for (int cv = 0;cv <= size - 1;cv = cv + 1) {
if (out_array[y] == bb[cv]) {
case_n = 1;
match = cv;
std::cout << "matched letter: " << bb[match] << std::endl;//debug
std::cout << "letter index: " << match << std::endl;//debug
std::cout << "case_n: " << case_n << std::endl;//debug
}
}
}
if (case_n == 0) {
out_array[y] = a[match];
std::cout << "replacement letter: " << a[match] << " | new character: " << out_array[y] << std::endl;//debug
}
if (case_n == 1) {
std::cout << "replacement letter: " << b[match] << " | new character: " << out_array[y] << std::endl;//debug
out_array[y] = b[match];
}
}
if (isdigit(out_array[y])) {
for (int o = 0;o <= size - 1;o = o + 1) {
if (out_array[y] == cc[o]) {
match = o;
std::cout << "matched letter: " << cc[match] << std::endl;//debug
std::cout << "letter index: " << match << std::endl;//debug
}
}
out_array[y] = c[match];
std::cout << "replacement number: " << c[match] << " | new character: " << out_array[y] << std::endl;//debug
}
std::cout << "- - - - - - - -" << std::endl;
}
std::cout << "original text: " << "\n" << original << "\n" << std::endl;
std::cout << "encrypted text: " << "\n" << out_array << std::endl;
delete[] out_array;
return 0;
}
int main() {
const int alpha_size = 27;
const int num_size = 11;
char l_a_set[] = "abcdefghijklmnopqrstuvwxyz";
char cap_a_set[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char n_a_set[] = "0123456789";
std::cout << "sizeof alpha_set: " << std::endl;//debug
char lower[alpha_size] = "mnbvcxzasdfghjklpoiuytrewq";
char upper[alpha_size] = "POIUYTREWQASDFGHJKLMNBVCXZ";
char num[num_size] = "9876543210";
int p_run; //control variable. 1 == running, 0 == not running
int b[alpha_size]; //array with values expressed as index numbers
std::string mode;
int m_set = 1;
while (m_set == 1) {
std::cout << "Enter 'auto' for automatic cypher generation." << std::endl;
std::cout << "Enter 'manual' to manually enter in a cypher. " << std::endl;
std::cin >> mode;
std::cin.ignore(1);
std::cin.clear();
if (mode == "auto") {
p_run = 2;
m_set = 0;
}
if (mode == "manual") {
p_run = 3;
m_set = 0;
}
}
if (p_run == 2) { //automatic mode
std::cout <<"lower cypher: " << lower << "\n" << "upper cypher: " << upper << "\n" << "number cypher: " << num << std::endl;//debug
run_cypher(lower,upper,num,l_a_set,cap_a_set,n_a_set);
return 0;//debug
}
while (p_run == 3) {//manual mode
return 0;//debug
}
return 0;
}
For example, using an array containing “mnbvcxzasdfghjklpoiuytrewq” as the cipher for lower case letters, I get “mnbv” if the input is “abcd”. This is correct.
If the input is “a long word”, I get “m gggz zzzv” as the output when it should be “m gkjz rkov”. Sort of correct but still wrong. If I use “this is a very very long sentence that will result in the program failing” as the input, I get "uas” as the output, which is completely wrong. The program still runs but it fails to function as intended. So as you can see, it does work, but not on any text strings that are remotely long. Is this a memory problem or did I make horrible mistake somewhere?
For your specific code, you should run it through a memory checking tool such as valgrind, or compile with an address sanitizer.
Here are some examples of memory problems that most likely won't crash your program:
Forgetting to delete a small object, which is allocated only once in the program. A memory leak can remain undetected for decades, if it does not make the program run out of memory.
Reading from allocated uninitialized memory. May still crash if the system allocates objects lazily at the first write.
Writing out of bounds slightly after an object that sits on heap, whose size is sizeof(obj) % 8 != 0. This is so, since heap allocation is usually done in multiples of 8 or 16. You can read about it at answers of this SO question.
Dereferencing a nullptr does not crash on some systems. For example AIX used to put zeros at and near address 0x0. Newer AIX might still do it.
On many systems without memory management, address zero is either a regular memory address, or a memory mapped register. This memory can be accessed without crashing.
On any system I have tried (POSIX based), it was possible to allocate valid memory at address zero through memory mapping. Doing so can even make writing through nullptr work without crashing.
This is only a partial list.
Note: these memory problems are undefined behavior. This means that even if the program does not crash in debug mode, the compiler might assume wrong things during optimization. If the compiler assumes wrong things, it might create an optimized code that crashes after optimization.
For example, most compilers will optimize this:
int a = *p; // implies that p != nullptr
if (p)
boom(p);
Into this:
int a = *p;
boom(p);
If a system allows dereferencing nullptr, then this code might crash after optimization. It will not crash due to the dereferencing, but because the optimization did something the programmer did not foresee.

weird glm::mat2x4 assignment behaviour

I am trying to load freetype chars, stuff them into a texture as subimages and then render them instanced.
While most of it seems to work, right now I have a problem with storing the texture coordinates into a glm::mat2x4 matrix.
As can be seen below each character has a struct with information I right now deem necessary, including a matrix called face, which should store the texture coordinates.
But when it comes to assigning the coordinates, after leaving the loop in which it takes place, suddenly all the values go crazy, without any (wanted/ intended) operation taking place from my side.
After creating the texture atlas with freetype and putting all my structs into the map, I assign the width and height of my texture aw & ah to a storage class called c_atlas.
I calculate the texture coordinates in the loop shown below, make the glm::mat2x4 a 0.0f matrix and then stuff them into it. Couting them into the console gives the values I want.
After leaving the for loop I start another one, browsing over the matrix and cout them into the console, which gives me more or less random values in the range of e^-23 to e^32.
All of this happens in namespace foo and is called in a constructor of a class in the same namespace (sth. like this:)
foo::class::constructor()
{
call_function();
}
int main()
{
foo::class c;
c.call_function();
}
I crafted a minimum working example, but unfortunatly I am not able to replicate the error.
So I have the following loop running (a part of call_function():
namespace foo
{
namespace alphabet
{
const char path_arial[] = "res/font/consola.ttf";
class character
{
public:
glm::vec2 advance;
glm::vec2 bearing;
glm::vec2 size;
glm::vec2 offset;
glm::mat2x4 face;
};
std::map<char, character> char_map;
FT_Library m_ftlib;
FT_Face m_ftface;
GLuint m_VBO, m_VAO;
}
c_atlas ascii;
}
void foo::call_function()
{
//creating all the charactur structs with freetype and store them in the char_map
std::ofstream f("atlas_data.csv", std::ios::openmode::_S_app);
f << "letter;topleft.x;topleft.y;topright.x;topright.y;bottomright.x;bottomright.y;bottomleft.x;bottomleft.y" << std::endl;
for(auto c : alphabet::char_map)
{
std::cout << "b4: " << c.second.offset.x;
c.second.offset /= glm::vec2(aw,ah);
std::cout << "\nafter: " << c.second.offset.x << std::endl;
glm::vec2 ts = c.second.size/glm::vec2(aw,ah);
//couts the right values
uint16_t n = 0;
c.second.face = glm::mat2x4(0.0f);
for(uint16_t i = 0; i < 4; ++i)
{
std::cout << c.first << " at init:\n";
std::cout << c.second.face[0][i] << "\n";
std::cout << c.second.face[1][i] << std::endl;
}
//couts the right values
c.second.face[0][n++] = c.second.offset.x;
c.second.face[0][n++] = c.second.offset.y;
c.second.face[0][n++] = c.second.offset.x+ts.x;
c.second.face[0][n++] = c.second.offset.y;
n = 0;
c.second.face[1][n++]= c.second.offset.x+ts.x;
c.second.face[1][n++] = c.second.offset.y+ts.y;
c.second.face[1][n++] = c.second.offset.x;
c.second.face[1][n++]= c.second.offset.y+ts.y;
for(uint16_t i = 0; i < 4; ++i)
{
std::cout << c.first << " assigned:\n";
std::cout << c.second.face[0][i] << "\n";
std::cout << c.second.face[1][i] << std::endl;
}
//still couts the right values
f << (char)c.first << ";" << c.second.face[0].x << ";" << c.second.face[0].y << ";" << c.second.face[0].z << ";" << c.second.face[0].w << ";" << c.second.face[1].x << ";" << c.second.face[1].y << ";" << c.second.face[1].z << ";" << c.second.face[1].w << std::endl;
//the file also have the right values
}
f.close();
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
//yet here all the values totally off track, i.e. e^32 or e^-23 (while they should all be between 0.01f - 1.0f)
for(auto i : alphabet::char_map)
{
std::cout << "\ntopleft:\n";
std::cout << "X: " << i.second.face[0].x << " | " << "Y: " << i.second.face[0].x;
std::cout << "\ntopright:\n";
std::cout << "X: " << i.second.face[0].z << " | " << "Y: " << i.second.face[0].w;
std::cout << "\nbotleft:\n";
std::cout << "X: " << i.second.face[1].x << " | " << "Y: " << i.second.face[1].x;
std::cout << "\nbotright:\n";
std::cout << "X: " << i.second.face[1].z << " | " << "Y: " << i.second.face[1].w;
}
}
my mwe:
#include <iostream>
#include <string>
#include "glm/glm.hpp"
#include "GL/gl.h"
#include <map>
struct bin
{
glm::mat2x4 mat;
};
int main( int argc, char *argv[] )
{
std::map<char, bin> bucket;
uint16_t r = 0;
for(uint16_t n = 0; n < 7; ++n)
{
glm::vec4 v = glm::vec4(0.12128f, 0.12412f, 0.15532f, 0.23453f);
bin b;
r = 0;
b.mat[0][r++] = v.x;
b.mat[0][r++] = v.y;
b.mat[0][r++] = v.z;
b.mat[0][r++] = v.w;
r = 0;
b.mat[1][r++] = v.x;
b.mat[1][r++] = v.y;
b.mat[1][r++] = v.z;
b.mat[1][r++] = v.w;
bucket[n] = b;
}
for(auto it : bucket)
{
r = 0;
std::cout << "0:\t" << it.second.mat[0][0] << "\t" << it.second.mat[0][1] << "\t" << it.second.mat[0][2] << "\t" << it.second.mat[0][3] << "\n";
r = 0;
std::cout << "1:\t" << it.second.mat[1][0] << "\t" << it.second.mat[1][1] << "\t" << it.second.mat[1][2] << "\t" << it.second.mat[1][3] << std::endl;
}
return 0;
}
Right now I am totally lost, especially as my mwe works fine.
I am clueless what goes wrong after leaving the for-loop, so thanks for any thought on that!
Indeed, I could just rewrite that section and hope it would work - as my mwe does. But I would like to find out/ get help on finding out what exactly happens between the "assign" for loop and the "retrieve" for loop. Any ideas on that?
I made it work for me now:
Appartenly assigning the values this way:
for(auto c : alphabet::char_map)
{
c.second.face[0][n++] = c.second.offset.x;
//and so on
}
Did not work properly (for whatever reason..)
Changing this into a for(uint16_t i = 32; i < 128; ++i) worked for me. Also it was just the assigning loop, the auto-iterating ofer the map elsewhere works just fine.

C++: Copying an element from an unordered_set to a vector

Background: I am implementing the nearest neighbor algorithm for the Traveling-Salesman-Problem. I need to calculate the distance traveled for the tour as well as keep track of the order of points visited. I have defined a point class with instance variables x and y and a function calcDist for calculating the distance between two points. I start by storing all of the points in a std::unordered_set named points, creating an empty std::vector named path to store the tour path, and assigning the starting point to startPoint, and pass these to my nearestNeighbor() function:
void nearestNeighbor(unordered_set<Point, PointHasher> points, vector<Point> &path, Point startPoint) {
// Declare variables
unordered_set<Point, PointHasher>::iterator it;
Point currentLocation, possibleNeighbor, nearestNeighbor;
double totalDist = 0;
int pointsCount = path.capacity() - 1;
// Set the starting location
it = points.find(startPoint);
currentLocation = *it;
path[0] = currentLocation;
points.erase(currentLocation);
cout << "Start location: " << path[0].x << ", " << path[0].y << endl;
// Create the path
for (int i = 1; points.size() > 0; i++) {
double minDist = -1;
// Find the current location's nearest neighbor
for (it = points.begin(); it != points.end(); it++) {
possibleNeighbor = *it;
int currentDist = currentLocation.calcDist(possibleNeighbor);
if (minDist == -1 || currentDist < minDist) {
minDist = currentDist;
nearestNeighbor = possibleNeighbor;
}
}
// Record nearest neighbor data and prepare for the next iteration
currentLocation = nearestNeighbor;
path[i] = currentLocation;
points.erase(currentLocation);
totalDist += minDist;
cout << "Nearest neighbor: " << path[i].x << ", " << path[i].y << endl;
}
// Return to the starting location
path[pointsCount] = startPoint;
cout << "End location: " << startPoint.x << ", " << startPoint.y << endl;
cout << "Path:" << endl;
for (int i = 0; i < path.size(); i++) {
cout << path[0].x << ", " << path[0].y << endl;
}
cout << "Total distance: " << totalDist << endl;
}
The problem is that once the program exits the outer for loop, all the points in path are overwritten somehow. To see what I mean, here is the output:
Start location: 3, 4
Nearest neighbor: 6, 8
Nearest neighbor: 11, 7
Nearest neighbor: 50, 8
End location: 3, 4
Path:
3, 4
3, 4
3, 4
3, 4
3, 4
Total distance: 49
Press any key to continue . . .
I am thinking this either has to be a problem with pointers/addresses of the vector elements, or something with scope since the problem happens after exiting the for loop. I have even tried printing the path[1] after each iteration to see when it gets changed, but it is correct throughout the loop, and only changes in the output at the end. Any thoughts? I am stumped. And if you have made it this far, thank you very much for your time.
you are always outputing the coordinates of path[0] man
for (int i = 0; i < path.size(); i++) {
cout << path[0].x << ", " << path[0].y << endl;
}
You have
for (int i = 0; i < path.size(); i++) {
cout << path[0].x << ", " << path[0].y << endl;
}
This doesn't iterate through i. Change your 0 to i and you'll likely see something more helpful:
for (int i = 0; i < path.size(); i++) {
cout << path[i].x << ", " << path[i].y << endl;
}
Edit: Change path[i] = currentLocation; to path.push_back(currentLocation); - this will automatically increase the size of your path vector to fit the new elements.
void nearestNeighbor(
unordered_set<Point, PointHasher> points,
vector<Point> &path,
Point startPoint,
double &totalDist) // note the new variable passed here
{
// Declare variables
unordered_set<Point, PointHasher>::iterator it;
Point currentLocation, possibleNeighbor, nearestNeighbor;
// double totalDist = 0; Remove this line
// int pointsCount = path.capacity() - 1; And this
// Set the starting location
it = points.find(startPoint);
currentLocation = *it;
path.push_back(currentLocation); // Changed this line
points.erase(currentLocation);
cout << "Start location: " << path[0].x << ", " << path[0].y << endl;
// Create the path
for (int i = 1; points.size() > 0; i++) {
double minDist = -1;
// Find the current location's nearest neighbor
for (it = points.begin(); it != points.end(); it++) {
possibleNeighbor = *it;
int currentDist = currentLocation.calcDist(possibleNeighbor);
if (minDist == -1 || currentDist < minDist) {
minDist = currentDist;
nearestNeighbor = possibleNeighbor;
}
}
// Record nearest neighbor data and prepare for the next iteration
currentLocation = nearestNeighbor;
path.push_back(currentLocation); // And this line
points.erase(currentLocation);
totalDist += minDist;
cout << "Nearest neighbor: " << path[i].x << ", " << path[i].y << endl;
}
// Return to the starting location
path.push_back(startPoint); // And here also!
cout << "End location: " << startPoint.x << ", " << startPoint.y << endl; // This I didn't change,
// but perhaps you should make it reflect the last point in the vector,
// not the start point which is supposed to be the last point in the vector
cout << "Path:" << endl;
for (int i = 0; i < path.size(); i++) {
cout << path[i].x << ", " << path[i].y << endl;
}
cout << "Total distance: " << totalDist << endl;
}
I do not see any place which grows the size of the path vector.
I suspect that you're passing an empty std::vector, for the second argument, and as soon as you hit path[0]=currentLocation; ... undefined behavior.
Also, I don't think that capacity() does what you think it does.
That, and, as others have pointed out, you're not outputing the contents of the array correctly, but that's a minor problem. The major problem here is that this program is likely scribbling over and corrupting the heap.

Adding new objects to dynamic array

I am trying to write function to add objects name Hotel to dynamically allocated array. Problem is, while my code can add the first one, it fails to add anything further than that. Here is the code responsible for adding new objects.
void HotelReservationSystem::addHotel( const std::string name, const int numFloors, const int *numRooms)
{
if ( hotelNum == 0 && hotels == NULL){
hotels = new Hotel[1];
Hotel hotelA ( name, numFloors, numRooms);
hotels[0] = hotelA;
hotelNum++;
std::cout << "Hotel " << name << " is added." << std::endl;
return;
}
for (int x = 0; x < hotelNum; x++){
if ( name == hotels[x].getName())
std::cout << "\n" << "Hotel " << name << " already exists." << std::endl;
return;
}
Hotel* temp = new Hotel[hotelNum+1];
for ( int x = 0; x < hotelNum; x++){
temp[x] = hotels[x];
}
temp[hotelNum] = Hotel ( name, numFloors, numRooms);
delete [] hotels;
hotels = temp;
hotelNum++;
std::cout << "Hotel " << name << " is added." << std::endl;
}
So far i cant detect anything wrong with this code.
for (int x = 0; x < hotelNum; x++){
if ( name == hotels[x].getName())
std::cout << "\n" << "Hotel " << name << " already exists." << std::endl;
return;
}
Here, the return is not part of the if statement. Your code will just return in the first iteration. You need to put braces around those two lines.
Of course, as the comments say, you shouldn't be doing memory management like this yourself. Use std::vector instead. Your function would become only a few lines.
You don't seem to have any declaration for the variable "hotels".