0

I tried to write a simple class that represents polynomial in CPP but I have a problem probably with freeing the memory and I can`t find any memory leak. Here is a sample of my code, header:

#pragma once
#include <iostream>
using namespace std;

class wielomian
{
    int n;
    double* a;
public:
    wielomian();
    wielomian(int k);
    wielomian(int k, double* t);
    ~wielomian();
    wielomian& operator=(const wielomian& a);
    friend wielomian operator*(const wielomian& a, const wielomian& b);
    friend ostream& operator<<(ostream& out, const wielomian& a);
    friend istream& operator>>(istream& in, wielomian& a);
}

Definitions of methods and functions

#include <iostream>
using namespace std;
#include "wielomian.h"

wielomian::wielomian() : n(0)
{
    a = new (nothrow) double;
    if (!a)
        return;
    a[0] = 1;
}
wielomian::wielomian(int k) : n(k)
{
    a = new (nothrow) double[k + 1];
    if (!a)
        return;
    for (int i = 0; i <= n; i++)
        a[i] = 1;
}
wielomian::wielomian(int k, double* t): n(k)
{
    a = new (nothrow) double[k + 1];
    if (!a)
        return;
    for (int i = 0; i <= n; i++)
        a[i] = t[i];
}

wielomian::~wielomian()
{
    delete[] a;
}

wielomian operator*(const wielomian& a, const wielomian& b)
{
    wielomian c(a.n + b.n);
    for (int i = 0; i <= c.n; i++)
        c.a[i] -= 1;
    for (int i = 0; i <= a.n; i++)
        for (int j = 0; j <= b.n; j++)
            c.a[i + j] += b.a[j] * a.a[i];
    return c;
}

ostream& operator<<(ostream& out, const wielomian& a)
{
    for (int i = 0; i < a.n; i++)
        out << a.a[a.n - i] << "x^" << a.n - i << "+";
    out << a.a[0] << endl;
    return out;
}

istream& operator>>(istream& in, wielomian& a)
{
    int p;
    cin >> p;
    a.n = p;
    delete[] a.a;
    a.a = new (nothrow) double[p + 1];
    if (!a.a)
        cout << "Problem with memory allocation" << endl;
    for (int i = 0; i <= a.n; i++)
    {
        cin >> p;
        a.a[i] = p;
    }
    return cin;
} 

wielomian& wielomian::operator=(const wielomian& b)
{
    if (n != b.n)
    {
        delete[] a;
        a = new (nothrow) double[b.n+1];
        if (!a)
            cout << "Problem with memory allocation" << endl;
        n = b.n;
    }
    for (int i = 0; i <= b.n; i++)
        a[i] = b.a[i];
    return *this;
}

and finally main:

#include <iostream>
using namespace std;
#include "wielomian.h"

int main()
{
    double z[4] = { 1,2,3,4 };
    wielomian p, a(2), x(3, z);
    cout << p << x << a << endl;

    wielomian e;
    e = a * x;
    cout << e << endl;
}

When the destructor is commented out everything is working fine so that is why im guessing there is a problem with memory allocation. If someone can spot any mistake in my code I would be more than happy. Thanks in advance

EDIT: Problem is solved thanks to your answers, I completely forgot about copy constructor and also delete[] wasnt working for polynomials with one element. Thank you :)

piotrek4
  • 1
  • 2
  • 2
    Why not `std::vector`? – eerorika May 01 '22 at 17:34
  • 1
    If you must handle allocation manually (`std::vector` is much better), this is a problem: `a = new (nothrow) double;` You use `delete[]` unconditionally in the destructor, so you *must* use array-`new` consistently. Change it to `a = new (nothrow) double[1];`; allocates the same amount of memory, and consistent with `delete[]`. – ShadowRanger May 01 '22 at 17:49

1 Answers1

2

The source of the problem is that operator* returns a wielomian by value, but class wielomian does not have a custom copy constructor.

The default copy constructor is simply copying the data members including the pointer a, and now you'll have 2 objects using the same pointer. The destructor of the first will free the memory, and then when the destructor of the second will attempt to free the same memory you get a double-free bug (How to track down a "double free or corruption" error).

More generally: whenever your class is managing resources manually (like you do with the memory for a data member), you must be aware of the rule of 3/5/0: The rule of three/five/zero.

Another issue is the mismatch between new and delete[] as noted by @ShadowRanger.

But even if these problems can be fixed, as @eerorika noted in the comment above, using std::vector will be more robust and will enable you to avoid the problem altogether (it will allow you to shift from the rule of 3/5 to 0 - see the link above).

wohlstad
  • 12,661
  • 10
  • 26
  • 39
  • 2
    If the OP won't use the Rule of Zero (by using `std::vector` and omitting copy/move constructors, copy/move assignment, and destructor), they need to know the [Rule of 3/5](https://en.cppreference.com/w/cpp/language/rule_of_three) to understand *why* this is a problem in general, not something specific to their code. I also strongly suspect the mismatch between non-array `new` and `delete[]` in some use cases adds additional heap corruption. – ShadowRanger May 01 '22 at 17:52
  • @ShadowRanger - good point - updated my answer. – wohlstad May 01 '22 at 17:57