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.
Related
I just wrote my first copy constructor and copy operator, and I'm trying to assign an object instance to an array like so:
Agent agent = Agent(navmesh, rb, m_maxPathSize);
Agent tmp = agent; // DEBUG
m_agents[idx] = agent;
The copy constructor seems to be working fine, since tmp is a perfect copy of agent (with a newly assigned m_path pointer). But when I assign agent to m_agents[idx], the latter consists of what I'd expect from the default constructor (m_path == 0, m_alive == false).
My constructors look like this:
Agent() { m_path = 0; m_alive = false; };
Agent::Agent(NavMeshNavigator* navmesh, RigidBody* rb, int maxPathSize)
: m_rb(rb), m_navmesh(navmesh), m_maxPathCount(maxPathSize)
{
m_path = new float3[maxPathSize];
};
Agent::Agent(const Agent &a)
{
memcpy(this, &a, sizeof(Agent));
if (m_path)
{
float3* oldptr = m_path;
m_path = new float3[m_maxPathCount];
memcpy(m_path, oldptr, m_maxPathCount * sizeof(float3));
}
}
Agent& Agent::operator=(const Agent &a) { return Agent(a); }
Agent::~Agent() { if (m_path) delete[] m_path; };
...
protected:
float3* m_path;
bool m_alive = true;
The constructor allocates memory for m_path using new[], the destructor frees it with delete[], the copy operator calls the copy constructor, and the copy constructor first memcopies the original before allocating a new m_path array.
In my test case, idx == 0, so that can't be it. I originally used malloc instead of new[] but got the same results. I'd say the problem is in my copy constructor/operator since I have no experience with that, but then why does it work perfectly on tmp?
EDIT:
The m_agents array is declared and destroyed like this:
NavMeshAgents(int maxAgents, int maxAgentPathSize)
: m_maxAgents(maxAgents), m_maxPathSize(maxAgentPathSize)
{
m_agents = new Agent[maxAgents];
};
~NavMeshAgents() { if (m_agents) delete[] m_agents; m_agents = 0; };
As #Evg #HolyBlackCat and #Adrian-Reinstate-Monica explained in the comments, new[] calls the default constructor for all its members. Agent tmp = agent calls the copy constructor, whereas tmp = agent would've called the assignment operator (tmp.operator=(agent)). My assignment operator was wrong, it should initialize this (and then return *this rather than return an instance.
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 tried to search same questions, but not one helped me. When I run program I get the "A Buffer Overrun has occurred..." error.
Constr:
Player(char* n)
{
length = strlen(n);
name = new char[length+1];
for(unsigned int i(0); i < length; i++)
name[i] = n[i];
name[length] = '\0';
}
Destr:
~Player(void)
{
delete [] name;
}
I've NULL terminated string and don't get out of bounds, what is problem?
There's no obvious error in the code you've posted, but trying to manage dynamic memory by juggling raw pointers will almost inevitably lead to errors like this.
Perhaps you haven't correctly implemented or deleted the copy constructor and copy-assignment operator, per the Rule of Three. In that case, copying a Player object will give two objects with pointers to the same array; both of them will try to delete that array, giving undefined behaviour.
The simplest solution is to manage your string with a class designed for managing strings. Change the type of name to std::string, and then the constructor can simply be something like
explicit Player(std::string const & n) : name(n) {}
and there's no need to declare a destructor (or move/copy constructor/assignment operators) at all.
So... a solution by using an std::string has been provided, but let me give another solution, keeping your member variables intact.
The problem is this. Suppose you have this code somewhere:
Player p1("Bob"); // Okay
Player p2("Annie"); // Okay
p2 = p1; // Oops! (1)
Player p3(p1); // Oops! (2)
At (1), the method Player& Player::operator=(const Player&) is called. Since you didn't provide one, the compiler generates one for you. When it does, it simply assumes that it may copy over all member variables. In this case, it copies over Player::name and Player::length. So, we have p1.name == p2.name. Now when the destructor of p2 is called, the allocated memory pointed to by p2.name is deleted. Then when the destructor of p1 is called, the same memory will be deleted (since p1.name == p2.name)! That's illegal.
To fix this, you can write an assignment operator yourself.
Player& Player::operator = (const Player& other)
{
// Are we the same object?
if (this == &other) return *this;
// Delete the memory. So call the destructor.
this->~Player();
// Make room for the new name.
length = other.length;
name = new char[length + 1];
// Copy it over.
for (unsigned int i = 0; i < length; ++i) name[i] = other.name[i];
name[length] = '\0';
// All done!
return *this;
}
At (2), the same problem occurs. You do not have a copy constructor, so the compiler generates one for you. It will also assume that it may copy over all the member variables, so when the destructors get called, they'll try to delete the same memory again. To fix this, also write a copy constructor:
Player::Player(const Player& other)
{
if (this == &other) return;
length = other.length;
name = new char[length + 1];
for (unsigned int i = 0; i < length; ++i) name[i] = other.name[i];
}
At the end of the day you should use an std::string though.
I haven't been able to find a good answer to this question.
I'm working on a C++ program and I'm trying to implement a function named copy which takes a reference to another object as an argument. Then, it returns a deep copy of this object.
Some background on my project: the Scene class contains a dynamic array (called "Images") of pointers to either NULL or an instance of the Image class, which is not shown here - but works as it should (it inherits all of its methods from a third party library, EasyBMP)
The reason I'm doing this is to avoid duplicating code in two places, but it's very possible that I'm taking the wrong approach.
I call this function in my assignment operator:
Scene const & Scene::operator=(Scene const & source)
{
if (this != &source) {
clear();
copy(source);
}
return *this;
}
And my copy constructor:
Scene::Scene(Scene const & source)
{
copy(source);
}
Finally, my copy() method looks like this:
Scene const & Scene::copy(Scene const & source)
{
Scene res(source.Max);
for (int i=0; i<res.Max; i++)
{
delete res.Images[i];
if (source.Images[i] != NULL)
res.Images[i] = new Image(*(source.Images[i]));
else
res.Images[i] = NULL;
}
return res;
}
Currently, it does NOT work. One problem I can see is that I'm trying to return a variable that goes out of scope as soon as the copy function ends. I tried returning a reference before, but the compiler threw errors and this wouldn't help with the scope issue anyways.
But I'm not even sure that my logic is right, i.e. can you even do something like this in a constructor? Or should I just explicitly write out the code in the copy constructor and assignment operator (without implementing the helper method copy)?
I'm very new to C++ and pointers, so any guidance would be much appreciated.
There's a way easier and more idiomatic way to do what you want: the copy-and-swap idiom.
// N.B. Not tested, but shows the basic structure of the copy-and-swap idiom.
class Scene
{
public:
Scene(int)
{
// Initialize a pointer array of Images
}
~Scene()
{
// Get rid of our pointer array of Images
}
// Copy constructor
// N.B. Not exception safe!
Scene(const Scene& rhs) : imgPtrArray(new Image*[rhs.max])
{
// Perform deep copy of rhs
for (int i=0; i < rhs.max; ++i)
{
if (rhs.imgPtrArray[i] != 0)
imgPtrArray[i] = new Image(*(rhs.imgPtrArray[i]));
else
imgPtrArray[i] = 0;
}
}
// Copy assignment constructor
// When this is called, a temporary copy of Scene called rhs will be made.
// The above copy constructor will then be called. We then swap the
// members so that this Scene will have the copy and the temporary
// will destroy what we had.
Scene& operator=(Scene rhs)
{
swap(rhs);
return *this;
}
void swap(Scene& rhs)
{
// You can also use std::swap() on imgPtrArray
// and max.
Images** temp = imgPtrArray;
imgPtrArray = rhs.imgPtrArray;
rhs.imgPtrArray = temp;
int maxTemp = max;
max = rhs.max;
rhs.max = maxTemp;
}
private:
Images** imgPtrArray;
int max;
};
That being said, I highly recommend that you pick up a good introductory C++ book, which will cover the basics of implementing the copy constructor and copy assignment operators correctly.
Scene const & Scene::operator=(Scene const & source);
overloaded assignment operator copies the content of this to the argument received source. For copy there is no need to return any thing or to create a local object. Just make a member wise copy from this to source.
void Scene::copy(Scene const & source){
// Member wise copy from this to source
}
Rule of three should be helpful to better understand more about these.
So having
struct ResultStructure
{
ResultStructure(const ResultStructure& other)
{
// copy code in here ? using memcpy ? how???
}
ResultStructure& operator=(const ResultStructure& other)
{
if (this != &other) {
// copy code in here ?
}
return *this
}
int length;
char* ptr;
};
How to implement "copy constructor" and "assignment operator"? (sorry - I am C++ nube)
Update: sbi and others ask - why do I want to manually deal with raw memory? My answer is simple - In a students project I am part of now we use lots of C library's such as for example OpenCV OpenAL and FFmpeg and there are more to come. Currently using C++ we try to create a graph based direct show like cross platform library that would be helpful in live video broadcasting and processing. Our graph elements currently use char* and int pairs for data exchange. To cast data to subscribed elements we use raw memcpy now. I want to go further and make it possible for us to make our graph elements base C++ template. So that one graph element would be capable of of sharing current graph element data with other Graph elements and that data it shares would be a structure that would contain not one char* one int but any number of data fields and nearly any elements inside. So that is why I need to understand how to create a basic C++ structure that implements "copy constructor" and "assignment operator" for me to be capable to use new for us data casting algorithms like
void CastData(T item){
for(size_t i = 0 ; i < FuncVec.size(); i++){
T dataCopy = item;
FuncVec[i](dataCopy);
}
}
instead of currently used
void CastData(char * data, int length){
for(size_t i = 0 ; i < FuncVec.size(); i++){
char* dataCopy = new char[length];
memcpy(dataCopy, data, length);
FuncVec[i](dataCopy, length);
delete[] dataCopy;
}
}
You might want to explain why you want to manually deal with raw memory. I haven't done this in a long time, it's what std::string and std::vector where designed for:
struct ResultStructure
{
// nothing else needed
std::string data; // or std::vector<char>
};
But if you really need to do this the hard way (is this homework?), then be advised that it is, at first, surprisingly hard to get this right. For example, a naive implementation of the assignment operator might be like this:
// DON'T TRY THIS AT HOME!!
ResultStructure& ResultStructure::operator=(const ResultStructure& rhs)
{
delete[] ptr; // free old ressource
ptr = new char[rhs.length]; // allocate new resourse
std::copy(rhs.ptr, rhs.ptr+rhs.length, ptr; // copy data
length = rhs.length;
}
If someone accidentally assigns an object to itself (which might happen if all you have is two references and you don't suspect them to refer to the same object), then this will fail fatally.
Also, what if new throws an exception? (It might throw std::bad_alloc if memory is exhausted.) Then we have already deleted the old data and have not allocated new data. The pointer, however, still points at where the old data used to be (actually, I think this is implementation-defined, but I have yet to see an implementation that changes a ptr upon deletion), and the class' destructor (you knew that class would need a destructor, right?) would then attempt to delete a piece of data at an address where no data is allocated. That's Undefined Behavior. The best you can hope for is that it crashes immediately.
The easiest way to do this is to employ the Copy-And-Swap idiom:
struct ResultStructure
{
ResultStructure(const ResultStructure& other)
: ptr(new char[rhs.length]), length(rhs.length)
{
std::copy(rhs.ptr, rhs.ptr+rhs.length, ptr);
}
~ResultStructure() // your class needs this
{
delete[] ptr;
}
ResultStructure& operator=(ResultStructure rhs) // note: passed by copy
{
this->swap(rhs);
return *this
}
void swap(const ResultStruct& rhs)
{
using std::swap;
swap(length, rhs.length);
swap(ptr, rhs.ptr);
}
std::size_t length;
char* ptr;
};
Note that I have added a destructor, changed the assignment operator to pass the argument per copy (we need the copy constructor invoked to allocate memory), and added a swap member function. Per convention a swap() function never throws and is fast, preferably O(1).
I know that GMan's discussion of the Copy-And-Swap idiom is exhaustive enough to be and exhausting while mine is probably too terse for you, and you will likely not understand a lot of it at first, but try to persevere and to understand as much as possible.
If you use std::string, instead of char*, you would not even need to write operator= or copy-constructor. The compiler generated code would do your job very well.
But as a general solution (for some other scenario), use copy-and-swap idiom:
Copy-and-Swap Idiom
What is the copy-and-swap idiom?
Exceptional C++ by Herb Sutter has described these in great detail. I would recommend you to read items from this book. For the time being, you can read this article online:
Exception-Safe Generic Containers
The easy solution is to use a std::string instead of char* member.
Then the compiler-generated copy constructor and copy assignment operator just work.
As a rule, and especially as a novice, don't have raw pointer members.
Cheers & hth.,
As has been said, and as was recommending in the question this emanated from, you should probably reuse an existing container. At least the code would be right :)
For educational purposes though, let's examine this structure:
class Result
{
public:
private:
size_t length; // can't really be negative, right ?
char* data;
};
Here, we need explicit memory management. This implies, notably, following the Rule Of Three (say thanks to Fred)
Let's begin with actually building our object:
Result::Result(): length(0), data(0) {}
Result::Result(size_t l, char* d): length(0), data(0)
{
if (!d) { return; }
data = new char[l]; // this may throw, so we do it first
length = l;
memcpy(data, d, l);
}
Now we can implement the traditional operators:
// Swap
void Result::swap(Result& other)
{
using std::swap;
swap(length, other.length);
swap(data, other.data);
}
// Copy Constructor
Result::Result(Result const& other): length(0), data(0)
{
if (!other.length) { return; }
data = new char[other.length];
length = other.length;
mempcy(data, other.data, length);
}
// Assignemt Operator
Result& Result::operator=(Result other)
{
this->swap(other);
return *this;
}
// !IMPORTANT!
// Destructor
Result::~Result()
{
delete[] data; // use the array form of delete
// no need to test for nullity, it's handled
}
this is std::vector<char>'s job - or is this homework?
the vector would replace both length and the allocation behind ptr. the vector is the c++ idiom, and you'll not make friends with other c++ devs if you implement your classes like you've described. of course, there are corner cases, but standard containers such as vector are the default.
the vector knows how to copy chars as well as itself, and the implementations are optimized and tested.
here's how to explicitly implement copy ctor/assign using a vector:
struct ResultStructure {
ResultStructure(const ResultStructure& other) : d_chars(other.d_chars) {
}
ResultStructure& operator=(const ResultStructure& other) {
if (this != &other) {
this->d_chars = other.d_chars;
}
return *this;
}
std::vector<char> d_chars;
};
I think this should do the work:
struct ResultStructure
{
ResultStructure(const ResultStructure& other);
ResultStructure& operator=(const ResultStructure& other);
int length;
char* ptr;
};
ResultStructure::ResultStructure(const ResultStructure& other):length(other.length)
{
ptr = (char*)malloc(length);
memcpy(ptr, other.ptr, length);
}
ResultStructure& ResultStructure::operator=(const ResultStructure& other)
{
length = other.length;
ptr = (char*)malloc(length);
memcpy(ptr, other.ptr, length);
return *this;
}
Please remember about freeing ptr in destructor.
What is stored under ptr? If text, why not to use std::string? Anyway you can use std::vector. The constructors will be much easier then...
How is the memory to which ptr points allocated?
if using new, allocate with new, set length and then copy
other.length = length;
other.ptr = new char[length];
memcpy( other.ptr, ptr, length );
If you're allocating the memory with malloc, substitute a call to malloc in place of the call to new. If you're using some other memory scheme, figure it out. :)