Debug_VLD in VS2010 reveals some memory leaks that come from class member creation / initialization / deletion.
my_member is a data member with type double*. In constructor, I have
my_member = NULL ;
Then in some method, i need to allocate memory for my_member. I cannot do so in constructor,
since i dont know size of array yet, and/or size may different for different calls of the method. What i do in this method is checking if member is NULL. if so, i allocate space for it, if not, i can operate on array (changing value for its element with accesor []). It looks like
void MyClass::my_method()
{
if( my_member == NULL )
my_member = new double[n_dim] ;
for(int k = 0 ; k < n_dim ; k++ )
my_member[k] = k ;
}
and memory leak occurs at line my_member = new double[n_dim] ;.
In destructor, i have
delete[] my_member ;
what is wrong? how to do allocation properly ?
thanks!
Using std::vector<double> is the preferred way, but if you want to have raw double* and write copy constructor, move constructor and operator= "by hand", you should do something like this:
#include <assert.h> // for assert
#include <algorithm> // for std::swap
class MyClass
{
//
// Raw array
//
double * m_ptr; // raw pointer
size_t m_dim; // number of items in the array
public:
// Default constructor - creates empty vector
MyClass()
: m_ptr(nullptr)
, m_dim(0)
{
}
// Copy constructor
MyClass(const MyClass& src)
: m_ptr(nullptr)
, m_dim(0)
{
// Special case of empty source
if (src.m_dim == 0)
{
assert(src.m_ptr == nullptr);
return;
}
// Allocate and deep-copy from source
m_ptr = new double[src.m_dim];
m_dim = src.m_dim;
for (size_t i = 0; i < m_dim; i++)
m_ptr[i] = src.m_ptr[i];
}
// Move constructor: steal the "guts" from src
MyClass(MyClass&& src)
{
m_ptr = src.m_ptr;
src.m_ptr = nullptr;
m_dim = src.m_dim;
src.m_dim = 0;
}
// Destructor
~MyClass()
{
delete [] m_ptr;
}
// Unified operator=
MyClass& operator=(MyClass src)
{
std::swap(m_ptr, src.m_ptr);
std::swap(m_dim, src.m_dim);
return *this;
}
};
If there's any other place in the code where you set my_member to NULL without calling delete[], then yes. If you don't obey the rule of three (properly implemented copy constructor and assignment operator), you'll run into all sorts of trouble.
To prevent this, use a std::vector<double> instead, where you can do:
void MyClass::my_method()
{
my_member.resize(n_dim); // yay, learned something new here
for(int k = 0 ; k < n_dim ; k++ )
my_member[k] = k ;
}
That way, you're not managing memory, so there's no need for a destructor (unless it's virtual, in which case it can be empty).
Related
I am still somewhat new at c++, and I am a little confused about this.
Say we have struct struct_x that uses raw pointers as attributes. Should the raw pointers then be deleted in the copy assignment operator, when they are already allocated? Or should you just assign the new pointee to the pointer?
(I am aware that it is advised to use smart/unique/shared pointers).
Code example:
struct struct_x {
public:
// Some attributes.
char* m_arr nullptr;
size_t* m_len = nullptr;
size_t* m_alloc_len = nullptr;
// Default constructor.
struct_x() {
m_len = new size_t(0);
m_alloc_len = new size_t(0);
}
// Copy constructor.
// Treat "struct_x" as a unique pointer for this example.
struct_x(const struct_x& x) {
// Assign.
m_arr = new char[*x.m_alloc_len + 1];
memcpy(m_arr, x.m_arr,*x.m_len);
m_len = new size_t(*x.m_len);
m_alloc_len = new size_t(*x.m_alloc_len);
}
// Copy assignment operator.
void operator =(const struct_x& x) {
//
//
// OVER HERE
//
// Should the pointers be deleted when they are already allocated?
// Like:
if (m_arr != nullptr) { delete[] m_arr; }
if (m_len != nullptr) { delete m_len; }
if (m_alloc_len != nullptr) { delete m_alloc_len; }
// Or not?
// Assign.
...
}
}
Second question:
Do I need to delete the old m_arr after using memmove?
// Resize.
void resize(const len_t& req_len) {
using T = char; // only for this example.
if (req_len > m_alloc_len) {
if (m_alloc_len == 0) { m_alloc_len = req_len; }
m_alloc_len *= 16;
T* l_arr = new T [m_alloc_len + 1];
memmove(l_arr, m_arr, m_len);
// if (m_arr != nullptr && m_arr) { delete [] m_arr; } // Do i need to delete here, no right?
m_arr = l_arr;
}
}
If you are implementing a string-like class as an exercise, then m_len and m_alloc_len should not be pointers at all. Only m_arr should be a pointer. If you are not doing an exercise, you should be using std::string or perhaps std::vector<char>.
Having said that...
It is perfectly fine and necessary to delete owning raw pointers in assignment operators of resource-managing classes.
There is a caveat though. The assignment operator should be protected against self-assignment. If you do
my_object = my_object;
then without such protection your program will access deleted memory area. You want this:
void operator =(const struct_x& x) {
if (this != &x) {
// contents of your assignment operator
}
}
my_object = my_object is an unlikely assignment to appear in a program, but such things can and do happen, especially if there is indirection involved. Say when doing a[i] = a[j], it is perfectly reasonable to have i == j.
There are other (better) ways to protect against self-assignment. You will encounter them in due course. You probably need to learn about move semantics first.before
Lets take custom vector implementation as an example:
template<typename Object>
class myVector {
public:
explicit myVector(int size = 0) :
_size{ size },
_capasity{ size + SPARE_CAPACITY }
{
_buff = new Object[_capasity];
if (_size > 0) {
for (int i = 0; i < _size; i++) {
//_buff[i] = 0;
}
}
}
// more code
private:
Object * _buff = nullptr;
int _size;
int _capasity;
};
So my question is, how to make myVector be value-initialized in case I'll initialize it as:
int main() {
myVector<int> v02(5);
}
Here, it contains 5 int values, so I need it to be all zeros; same with other types. I commented out _buff[i] = 0; as it's specific to int. Please give me some hints.
It's as simple as
for (int i = 0; i < _size; i++)
_buff[i] = Object{};
Alternatively, you could get rid of the loop and add a pair of {} (or ()) here:
_buff = new Object[_capasity]{};
// ^^
But this option would value-initialize all _capasity objects, rather than the first _size ones, as noted by #bipll.
Also, note that if you want to mimic the behavior of std::vector, you need to allocate raw storate (probably std::aligned_storage) and call constructors (via placement-new) and destructors manually.
If Object is a class type, _buff = new Object[_capasity]; calls default constructors for all _capasity objects, rather than for the first _size objects as std::vector does.
Note that when calling
_buff = new Object[_capasity];
(btw, why have you moved this initialization out of init-list, into constructor body?) you already have default-initialized _capasity objects. Default initialization has the following effects here: while elements of scalar type would remain uninitialized (and reading from them UB), for class types you have already called _capasity constructors.
To avoid unnecessary constructions you have the following possible options, among others:
Use std::aligned_alloc to allocate non-initialized memory:
explicit myVector(std::size_t size = 0) :
size_{ size }
, capacity_{ size + SPARE_CAPACITY }
, buff_{std::aligned_alloc(alignof(Object), _capacity)}
{
if(!buff_) throw std::bad_alloc();
if(size) new (buff_) Object[size]{}; // empty braces answer your original query
}
Remember that again buff_ should be aligned_alloced when vector grows (can be std::realloc()ed for trivial types), and in destructor it should be std::free()d — and prior to that size_ objects inside it should be destructed (with an explicit call to ~Object()).
Change buff_'s type to something more trivial yet properly aligned:
using Storage = std::aligned_storage_t<sizeof(Object), alignof(Object)>;
Storage *buff_;
Object *data_ = nullptr;
public:
explicit myVector(std::size_t size = 0) :
size_{ size }
, capacity_{ size + SPARE_CAPACITY }
, buff_{new Storage(_capacity)}
{
if(size) data_ = new (buff_) Object[size]{};
}
Again, in destructor, objects should be manually destroyed, but this time buff_ can be simply delete[]d afterwards.
I have the following class:
class Matrix {
int *A;
int m, n;
...
};
Matrix::Matrix(int rows, int cols){
m = rows, n = cols;
A = new int[m*n];
}
Matrix::~Matrix(){
delete[] A;
}
I am trying to write a function which returns a Matrix object. In doing so, the default copy constructor is invoked, which means each the new returned object points to the same block of dynamically allocated memory as the one in the function. This causes the program to behave badly because this same memory gets deallocated when the object in the function goes out of scope.
How should I write my copy constructor? Is there a work around for this which doesn't require me to copy int array element-by-element?
Here's the function if it helps:
Matrix Matrix::submatrix(int r, int c){
if (m <= 1 || n <= 1)
return Matrix(0, 0); //return null matrix
Matrix T(m-1, n-1);
int ti = 0;
for (int i = 0; i < m; i++){
if (i == r) continue;
for (int j = 0; j < n; j++){
if (j == c) continue;
T.A[ti] = this->valueAt(i, j);
ti++;
}
}
return T;
}
For the class Matrix you also have to add a copy constructor and a copy assignment operator in order to work with dynamically allocated memory in the right way.
Let's start with a copy constructor. The basic version might look like this:
Matrix::Matrix(const Matrix& other) {
A = new int[other.m * other.n];
std::copy(A, A + other.m * other.n, other.A);
}
You just allocate a memory for A and then copy the contents.
Now, copy assignment operator:
Matrix& Matrix::operator=(const Matrix& other) {
int* nA = new int[other.m * other.n];
std::copy(nA, nA + other.m * other.n, other.A);
delete[] A;
A = nA;
return *this;
}
It's a bit trickier. The code above allocates a memory for a new matrix, copies the contents into the newly allocated memory and releases the old memory then updating A. It uses a temporary pointer in order to deal with potentially throwing new.
Then, you might add a move constructor and a move assignment operator as well.
And, as it is mentioned, the preferred way is to use STL containers like std::vector which manage their memory on their own.
Since you store the matrix efficiently in one large array, it is trivial to implement the copy constructor:
Matrix::Matrix(Matrix const& b)
: A(new int[b.m * b.n])
, m(b.m), n(b.n)
{
std::copy_n(b.A, b.m * b.n, A);
}
You may also like to store the array in std::unique_ptr<int[]>, so that it never leaks memory and protects you from accidentally copying it.
To implement the copy assignment I would suggest using swap:
void Matrix::swap(Matrix& b) {
using std::swap;
swap(A, b.A);
swap(m, b.m);
swap(n, b.n);
}
Matrix& Matrix::operator=(Matrix const& b) {
Matrix(b).swap(*this); // Re-use the copy constructor.
return *this;
}
You may also like to implement the move constructor and assignment in the similar fashion:
Matrix::Matrix(Matrix&& b)
: A(b.A)
, m(b.m), n(b.n)
{
b.A = nullptr;
}
Matrix::Matrix& operator=(Matrix&& b) {
Matrix(std::move(b)).swap(*this); // Re-use the move constructor.
return *this;
}
Alternatively, store the array as std::vector<int>. This way the compiler generated copy constructor, move constructor, the assignments and the destructor do the right thing for you. This is also known as rule-of-zero.
I am quiet new to memory management in C++. I made a BigInt class that is now fully implemented except for the destructor which is impacting performance of the program. However, when I try to implement the destructor my program crashes.
In the following code for multiplying BigInts:
BigInt& BigInt::operator*=(BigInt const& other) {
//copy of this and other
BigInt* tempThis = new BigInt(*this); //1st number
BigInt* tempOther = new BigInt(other); //2nd number
//create temps so we can use value of BigInt before it is changed
BigInt* sum = new BigInt(0); //holds the eventual answer
BigInt* i = new BigInt(0);
//add *this BigInt to sum otherTemp amount of times
//this will yield multiplication answer.
for (*i; *i < *tempOther; *i = *i + 1) {
*sum += *this;
}
*this = *sum;
return *this;
}
The destructor is called when *i = *i + 1 is called in the for loop and then I think it gets deleted in my destructor which looks like this:
// destructor
BigInt::~BigInt() {
delete[] this->bigIntVector;
}
// copy constructor
BigInt::BigInt(BigInt const& orig)
: isPositive(orig.isPositive)
, base(orig.base)
{
this->bigIntVector = new BigIntVector(*(orig.bigIntVector));
}
Once 'i' is deleted nothing works and the whole program breaks.
If someone could give me a few pointers about destructors and how to fix my problem it would be great help. Thanks.
In C++, the same (horrible) arithmetic could be implemented as follows.
BigInt& BigInt::operator*=(BigInt const& other)
{
if(other==0)
return other;
if(other> 1)
for(BigInt old=*this,i=1; i!=other; ++i)
operator+=old;
else if(other<0) {
BigInt old=*this;
*this=0;
for(BigInt i=0; i!=other; --i)
operator-=old;
}
return*this;
}
assuming that the constructor from int, the copy constructor, the increment operator++ and the addition operator+= are all properly implemented (as well as the destructor).
Unfortunately, you failed to give us more information, but your copy constructor and destructor are definitely broken:
this->bigIntVector = new BigIntVector(*(orig.bigIntVector));
is followed by
delete[] this->bigIntVector;
giving you undefined behaviour (allocating with new but deallocating with delete[] -- delete[] is for memory allocated with new[]). I suspect you meant to copy the memory from the original in the copy constructor. However, you don't. If
class BigInt {
size_t size=0; // number of some_types allocated
some_type*bigIntVector=nullptr; // ptr to memory allocated, if any
/* rest of class */
};
then the copy constructor could be implemented like (assuming size is non-static)
BigInt::BigInt(BigInt const&orig)
: size(orig.size() // copy size
, bigIntVector(size? new some_type[size] : nullptr) // allocate memory
{ std::memcpy(orig.bigIntVector, bigIntVector); } // copy memory
However, (almost) the same could be implemented much easier with
class BigInt
{
std::vector<some_type> bigIntVector;
public:
BigInt(BigInt const&) = default;
BigInt(BigInt &&) = default;
BigInt&operator=(BigInt const&) = default;
BigInt&operator=(BigInt &&) = default;
/ * rest of class */
};
when the copy and move constructors (as well as the respective assignment operators) are automatically correctly created for you. You only need to address the default constructor, for example
BigInt::BigInt() // default constructor
: bigIntVector(1,some_type(0)) {} // size=1, value=0
and the constructors from built-in integer types. If you're new to C++, avoid new and delete in favour of standard library containers.
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.