Weird bug when using vector destructor [duplicate] - c++

This question already has answers here:
Destructor being called twice when being explicitly invoked
(10 answers)
Closed 4 years ago.
So my code works fine when I do not call the destructor of the vector class. But it bugs out and my vector bugs out when I call the vector destructor. Can anyone explain to me why? From what I understand, adding the destructor line should not make any difference as I am just freeing the object once I used finished them. I'm compiling it online on the geekforgeeks ide if it helps.
#include <iostream>
#include <vector>
using namespace std;
//Function that converts from base 10 to another base given by user input
//And results are stored in the vector
int getRepresent(vector<int> &vec, int base, int num) {
if (num < base) {
vec.push_back(num);
return 1;
}
vec.push_back(num % base);
return 1 + getRepresent(vec, base, num / base);
}
//Compute the sum of squares of each digit
int computeSsd(int base, int num) {
vector<int> vec;
int len = getRepresent(vec, base, num);
int i;
int sum = 0;
for (i = 0; i < len; i++) {
sum += vec[i] * vec[i];
}
/*
for (auto x: vec) {
cout << x <<' ';
}
vec.~vector(); //the weird part that cause my vector to change once i add this line
*/
return sum;
}
int main() {
int size;
int i;
cin >> size;
for (i = 0; i < size; i++) {
int display;
int base;
int num;
cin >> display >> base >> num;
int ssd = computeSsd(base, num);
cout << display << ' ' << ssd << '\n';
}
return 0;
}

You shouldn't call the dsestructor yourself in this case*.
It will be called automatically, when the object goes out of scope.
What happened, is that you called the destructor yourself, then the destructor was called again automatically when the object went out of scope, which invoked Undefined Behavior (UB)! Think about it, when the destructor is called automatically, the object is already destructed!
*Is calling destructor manually always a sign of bad design?

Related

Having a problem with getting the right value with private variable

This is a program that takes an array and print the sum of the odd (named m_sumOdd) and even (named m_sumEven) numbers of that array using class. However when i run it and enter some values like (4, 6, 9, 3, 1) the m_sumEven returns 10 and m_sumOdd returns 2037769787. What's the problem with m_sumOdd ?
#include <iostream>
#include <string>
class myClass {
private:
int m_sumEven;
int m_sumOdd;
public:
myClass() {
m_sumEven = 0;
m_sumOdd = 0;
}
myClass(int arr[]) {
for (int i = 0; i < 5; i++)
{
if (arr[i] % 2 == 0) {
m_sumEven += arr[i];
}
else if (arr[i] % 2 != 0) {
m_sumOdd += arr[i];
}
}
print();
}
void print() {
std::cout << m_sumEven << "\t" << m_sumOdd << std::endl;
}
};
int main(){
int main_arr[5];
for (int j = 0; j < 5; j++)
{
std::cin >> main_arr[j];
}
myClass obj(main_arr);
std::cin.get();
}
From your comment:
the problem is from my uni textbook and it specify that the private variables shall be initialized in the default constructor and the other constructor find the sum
I'm not sure what solution the textbook is looking for, but there is a mechanism that allows one constructor to use another.
class myClass {
private:
int m_sumEven;
int m_sumOdd;
public:
myClass() {
m_sumEven = 0;
m_sumOdd = 0;
}
myClass(int arr[]): myClass() { // <-------
....
This is called delegating constructors. This makes your myClass(int arr[]) constructor use the myClass() constructor before continuing on.
When you do not initialize your variable in C++, the default value of that variable is whatever garbage value happens to already be in that memory location. So if you initialize your privates variables as zeros (as in your non-parameterized constructor), your problem will be solved.
The second constructor doesn't initialize the private variables like the first one.
m_sumEven = 0;
m_sumOdd = 0;
Put these to the second constructor as well.
Even better, put them at the declaration:
int m_sumEven = 0;
int m_sumOdd = 0;
And now you don't need the first constructor.
Unrelated: consider using std::initializer_list instead. This provides you a safe way to know how many items are passed to the constructor, while now you have a fixed 5 in mind which may change later.

How to initialize an array in a constructor c++

I need help with this code.
What I want is to make a parametric constructor and initialise/set the value of array in it.
Question: Make a class with arrays of integers and initialise it in a constructor. Then find the smallest and largest numbers using functions.
But I am stuck at how to initialise the array in the constructor.
I want to take data input in both ways
(1) By user, using cin
(2) By giving my own values
class Numbers
{
int Arr[3];
public:
Numbers() //default constructor
{
for (int i=0 ; i<=2 ; i++)
{
Arr[i]=0;
}
}
Numbers(int arr[]) //parameteric constructor
{
for (int i=0;i<=2;i++)
{
Arr[i]=arr[i];
}
}
};
int main()
{
int aro[3] = {0,10,5};
Numbers obj (aro);
return ;
}
The solution is pretty simple. I've made a new program from start again (for sake of understanding). According to your requirement, you wants to get input of array elements from the user dynamically and assign them to a constructor and use a method to print the highest value.
Consider the following code:
#include <iostream>
using namespace std;
const int N = 100;
class Numbers
{
int largest = 0;
public:
Numbers(int, int[]);
void showHighest(void)
{
cout << largest << endl;
}
};
Numbers::Numbers(int size, int arr[])
{
for (int i = 0; i < size; i++)
{
if (arr[i] > largest)
{
largest = arr[i];
}
}
}
int main(void)
{
int arrays[N], total;
cout << "How many elements? (starts from zero) ";
cin >> total;
for (int i = 0; i < total; i++)
{
cout << "Element " << i << ": ";
cin >> arrays[i];
}
Numbers n(total, arrays);
n.showHighest();
return 0;
}
Output
How many elements? (starts from zero) 3
Element 0: 12
Element 1: 16
Element 2: 11
16
Note: I've initialized a constant number of maximum elements, you can modify it. No vectors, etc. required to achieve so. You can either use your own values by removing the total and its followed statements and use only int arrays[<num>] = {...} instead. You're done!
Enjoy coding!
I suggest to use std::vector<int> or std::array<int>.
If you want initialize with custom values you can do std::vector<int> m_vec {0, 1, 2};
Thank you so much for your help. I was basically confused about how to use arrays in a constructor and use setters/getters for arrays in a class. But you all helped a lot. Thanks again.
Numbers(int arr[])
{
for (int i=0;i<=9;i++)
{
Arr[i]=arr[i];
}
Largest=Arr[0];
Smallest=Arr[0];
}
void Largest_Number()
{
header_top("Largest Number");
Largest=Arr[0]; //Using this so we make largest value as index zero
for (int i=0 ; i<=9 ; i++)
{
if(Arr[i]>Largest)
{
setLargest( Arr[i] );
}
}
cout<<"Largest Number: "<<getLargest()<<endl;
}

Garbage values are printed when I try to print the elements of an array using pointer

I have a class named mvector which has two private variables, num (denotes number of elements in the array), and an integer pointer to store the array address.
mvector has 2 public functions, get() and print() to get the elements of the array, and print them (respectively).
However, when I try to print the values, some values are correct, while others are garbage values.
#include<iostream>
using namespace std;
class mvector
{
private:
int num;
int *ele;
public:
void get();
void print();
};
void mvector::get()
{
cin>>num;
int data[num];
for(int i=0; i<num; i++)
{
cin>>data[i];
}
ele=data;
}
void mvector::print()
{
for(int i=0; i<num; i++)
{
cout<<*ele<<endl;
ele++;
}
}
int main()
{
mvector v1;
v1.get();
v1.print();
}
Input: 5 1 2 3 4 5
Expected Output: 1 2 3 4 5
Actual Output: 1 1 1877615960 4 5
The program does not make a great sense.
For example the variable length arrays is not standard C++ feature. So the declaration of the array
cin>>num;
int data[num];
is not correct.
Within the function get the data member ele is assigned with the address of the first element of a local array that will not be alive after exiting the member function. So using this pointer in the member function print invokes undefined behavior.
You have to define the array dynamically.
Moreover within the function print the pointer ele is incremented and loses its initial value. It means that you could call the function the second time
You should define a class with constructors and destructor.
More or less working code can look the following way.
#include <iostream>
class mvector
{
private:
size_t num = 0;
int *ele = nullptr;
public:
void get();
void print() const;
};
void mvector::get()
{
size_t n;
std::cin >> n;
if ( n != num )
{
delete [] ele;
ele = nullptr;
if ( n != 0 )
{
ele = new int[n];
}
num = n;
}
if ( num != 0 )
{
for ( size_t i = 0; i < num; i++)
{
std::cin >> ele[i];
}
}
}
void mvector::print() const
{
int *p = ele;
for ( size_t i = 0; i < num; i++ )
{
std::cout << *p << ' ';
++p;
}
std::cout << '\n';
}
int main()
{
mvector v1;
v1.get();
v1.print();
v1.get();
}
For the input like this
5
1 2 3 4 5
0
The output will be
1 2 3 4 5
and the allocated memory will be freed.
The line
ele=data;
is the source of your problems.
data is a local array, a non-standard VLA, but it is still a local array. When the function returns data is destructed and ele points to an object that is no longer valid. Accessing ele after the function returns is cause for undefined behavior. The garbage values you are seeing is just one symptom of undefined behavior.
You can change that function to use:
void mvector::get()
{
cin>>num;
ele = new int[num];
for(int i=0; i<num; i++)
{
cin>>ele[i];
}
}
That will solve your immediate problem. However, there are other issues you have to contend with when managing memory yourself. See http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three for additional details.

c++ two errors while compiling

I'm a beginner in c++ and I'm getting two errors in my code and I don't know how to fix them...
the first one
illegal indirection
and the second one is
'=' left operand must be a I-value. (in the line: ((ArrayPtr +i)+j)=rand()%55+1 )
Does anyone have an idea how to fix them? That's my code:
#include <iostream>
#include <math.h>
#include <time.h>
#include<iomanip>
#include<array>
#include <algorithm>
using namespace std;
const int AS = 6;
void FillingRandomly(int (*)[AS]);
void printing(int (*)[AS]);
int c;
int main()
{
int funny = 0;
int timpa = 0;
int counter = 0;
int Array[AS][AS];
srand(time(0));
FillingRandomly(Array);
cout << "The unsorted array is" << endl << endl;
printing(Array);
cout << "The sorted array is" << endl << endl;
printing(Array);
system("PAUSE");
return 0;
}
void FillingRandomly(int *ArrayPtr)
{
for(int i=0;i<AS;i++)
{
for (int j=0;j<AS;j++)
{
*(*(ArrayPtr +i)+j)=rand()%55+1;
}
}
}
void printing(int *Array)
{
for(int i=0;i<AS;i++)
{
for (int j=0;j<AS*AS;j++)
{
int counter = 0;
cout<<((Array[i] +j))<<setw(5);
if ((Array[i] +j)%AS == 0)
cout << endl << endl;
}
}
}
void forsorting(int *Brray, int funny)
{
int dice = 0;
int super = 0;
int space=0;
//Sorting Array[][] which is treated like Array[]
{
for (int pass = 0; pass < AS - 1; pass++) {
for (int k = 0; k < AS - 1; k++) {
int temp;
if(*(Brray+k)==*(Brray+k+1))
{
temp=*(Brray+k);
*(Brray+k)=*(Brray+k+1);
*(Brray+k+1)=temp;
}
}
}
}
}
By
*(*(ArrayPtr +i)+j)=rand()%55+1;
it seems you want
ArrayPtr[i][j] = (rand() % 55) + 1;
You can try something along the line of
int const offset = AS * i + j;
int const elem = (rand() % 55) + 1;
*(ArrayPtr + offset) = elem;
Your function signature is:
void FillingRandomly(int *ArrayPtr)
where you are telling to compiler that you are passing a simple pointer, but in the line:
*(*(ArrayPtr +i)+j)=rand()%55+1;
you are doing a double derreference, which is illegal and causing the compiler to complain
COMPLEMENT
I was seeing the comments in the other answer and, as what I need to write is bigger than the reserved commentary space, I decided to complement my own answer.
You defined Array as:
int Array[AS][AS];
Indeed, what you are doing is a promise to compiler that you will use Array as defined, but the compiler doesn't believe in you too much, so that any time you use Array the compiler will make sure that it is being used as declared.
The problem arises when you declare your FillingRandomly function. Here you are broking your promise and are trying to use Array by declaring a differente type. Note how you declare your function:
void FillingRandomly(int *ArrayPtr)
Due the fact that c++ supports function overloading, the compiler doesn't warn you until it initiate the linking phase, when it is unable to find a function whose signature is:
void FillingRandomly(int ArrayPtr[][AS])
note that both are different.
Once you are a beginner, the best way to keep your programs correctly is to keep your promise immutable. Bellow I show you a piece of your own code, correcting those issues for FillingRandomly function (you have to correct it for the others functions too):
const int AS = 6;
void FillingRandomly(int [][AS]); // Note that I've changed your prototype here
....
void FillingRandomly(int ArrayPtr[][AS]) // Keep your function signature the same as your prototype signature
{
for(int i=0;i<AS;i++)
{
for (int j=0;j<AS;j++)
{
ArrayPtr[i][j]=rand()%55+1; // Note how ArrayPtr is being used exactly as your promised early
}
}
}

Memory pointer cleared when returned with object

This has been destroying me for a while. I'm sure there's a reason for this:
chain operator+(chain c)
{
chain<Object> result;
for (int i = 0; i < length(); i++)
{
result.insert(*(Object*)(memory+(i*sizeof(Object))));
}
for (int i = 0; i < c.length(); i++)
{
result.insert(c[i]);
}
for (int i = 0; i < result.length(); i++) // This for loop successfully shows all objects in result
{
cout << result[i];
}
return result;
}
When the value is returned, ie:
chain<int> a;
cin >> a; // enter "5 6 7 8"
chain<int> b;
cin >> b; // enter "9 10 11 12"
chain <int> c = a+b;
cout << c; // Returns "0 0 7 8 9 10 11 12"
The first two numbers are always 0. I can't figure out why. This only happens when adding two chains together; if I cout a or b, I get all of the values.
I would really appreciate it if anyone has any info to share :)
EDIT**
Full Source
#ifndef CHAIN_H
#define CHAIN_H
#include <iostream>
#include <stdlib.h>
using namespace std;
template <class Object>
class chain
{
public:
chain(){
memorySize = 8;
memory = calloc(memorySize, sizeof(Object));
count = 0;
}
chain(Object item){
memorySize = 8;
memory = calloc(memorySize, sizeof(Object));
count = 0;
insert(item);
}
chain(chain & original){
memorySize = 8;
memory = calloc(memorySize, sizeof(Object));
count = 0;
for (int i = 0; i < original.length(); i++)
{
insert(original[i]);
}
}
~chain(){
free(memory);
}
chain operator+(chain c){
chain<Object> result;
for (int i = 0; i < length(); i++)
{
result.insert(this->operator[](i));
}
for (int i = 0; i < c.length(); i++)
{
result.insert(c[i]);
}
for (int i = 0; i < result.length(); i++)
{
cout << result[i];
}
return result;
}
Object & operator[](int pos){
return *(Object*)(memory+(pos*sizeof(Object)));
}
int length(){
return count;
}
void insert(Object item){
if (count == memorySize)
{
doubleMemory();
}
this->operator[](count) = item;
count++;
}
private:
int count;
int memorySize;
void * memory;
void doubleMemory(){
memorySize *= 2;
memory = realloc(memory, (memorySize*sizeof(Object)));
}
};
template <class Object>
ostream& operator<<(ostream& out, chain<Object>& c){
for (int i = 0; i < c.length(); i++)
{
out << c[i] << " ";
}
}
template <class Object>
istream& operator>>(istream& in, chain<Object>& c){
char ch;
int number = 0;
int sign;
while(ch != '\n')
{
ch = in.get();
if (ch == '-')
{
sign = 1;
}
else if (ch >= '0' && ch <= '9')
{
number *= 10;
number += (ch-48);
}
else if (ch == ' ' || ch == '\n')
{
number = sign == 1? 0 - number : number;
c.insert(number);
sign = 0;
number = 0;
}
}
}
#endif
Here's the code I'm testing against:
#include "chain.h"
using namespace std;
int main(){
chain<int> a, b, c;
chain<int> d(10);
chain<int> e(d);
cin >> a;
cout << endl;
cout << endl;
c = a+d;
cout << c;
}
~
The code you’ve shown isn’t the problem. The real problem is probably either in the copy constructor or the destructor of chain – maybe also in the insert method (or, on C++11, in the move constructor).
(It could also be in Object’s copy constructor but I think that’s unlikely.)
EDIT: Oh my. Don’t write such code in C++. It’s unsafe left, right and center. As long as Object is a POD you should be fine but if it isn’t this code yields undefined behaviour. In particular, it doesn’t call the proper constructors and destructors for the objects you store in your chain.
Furthermore, your copy constructor should take an argument of type chain const& since you’re not modifying the passed chain. This in turn requires that you make your class const correct by providing an appropriate const overload of operator [].
Finally and most glaringly, you violate the rule of three because you don’t implement operator = for your chain. Trying to assign one chain to another will consequently result in double frees.
Generally avoid calloc and free and use a standard container instead, or, if that’s not an option, use new[] plus a smart pointer like boost::shared_array to manage memory (but do not use delete[]).
Another thing, never use using namespace in a header file, it will pollute the namespace and lead to name conflicts in the weirdest places.
Well, I see the following problem regarding the copy-constructor. It seems to me that you want this to act as a copy-constructor:
chain(chain & original){
memorySize = 8;
memory = calloc(memorySize, sizeof(Object));
count = 0;
for (int i = 0; i < original.length(); i++)
{
insert(original[i]);
}
}
But it can't since the declaration of the method is wrong. You are missing the const modifier in the copy argument. If you don't include it, the compiler assumes that you are only declaring a normal constructor which works with a mutable reference, and this is not the copy-constructor you need to define following the
Rule of Three.
Just change this:
chain(chain & original){
to this:
chain(const chain & original){
This will probably solve a wrong memory handling, and hopefully you will get a different output in your program.