473,320 Members | 2,020 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

Copy constructor required for proper execution of operator+

So, I have not written c++ in quite a while and am trying to dig back in to it. I am running in to a weird situation and I am hoping someone might be able to explain it.

I have a class representing a three dimensional matrix of integers in which I am trying to implement the operator+ for addition of an integer to all elements of the matrix. The class signature looks like this,

Expand|Select|Wrap|Line Numbers
  1. class Matrix
  2. {
  3.     public:
  4.         Matrix();
  5.  
  6.         Matrix(const Matrix& _object);
  7.         Matrix(const unsigned int _iMax, const unsigned int _jMax, const unsigned int _kMax);
  8.  
  9.         ~Matrix();
  10.  
  11.         Matrix& operator=(const Matrix& rhs);
  12.  
  13.         Matrix& operator=(const int& rhs);
  14.  
  15.         Matrix operator+(const int& rhs) const;
  16. };
  17.  
When I first implemented this class I did not include the copy constructor. Without the copy constructor, if I ran the simple test code below I consistently saw an error indicating a memory violation. What was happening is when the object mat3 was destroyed the memory used internally to store the integer matrix had already been cleaned up.

Expand|Select|Wrap|Line Numbers
  1. int main(int argc, char* argv[])
  2. {
  3.     Matrix mat(5, 5, 5);
  4.     mat = 0;
  5.  
  6.     Matrix mat3;
  7.     mat3 = mat + 1;
  8.  
  9.     return 0;
  10. }
  11.  
I managed to track this down in the debugger to determine that the temporary object returned by operator+(int) actually used the same address for storage of the internal array of data that the object mat3 did. So, when the temporary object was cleaned up it deallocated the memory.

On a whim, I added the copy constructor to see if the behavior was different. Sure enough, when I define the copy constructor the compiler is converting the line,
Expand|Select|Wrap|Line Numbers
  1. mat3 = mat + 1
  2.  
to
Expand|Select|Wrap|Line Numbers
  1. mat3.operator=(new Matrix(mat.operator+(1)))
  2.  
thus inserting the call to the constructor. In this case everything works with no problems at all.

What I am wondering is if this should be required, or if I have a problem in the implementation of my + and = operators. I really dislike having yet another class instantiation and copy here since the internal matrix could be big. Hate to use the memory as well as have to copy the data.

My operators + and = are implemented as shown below,

Expand|Select|Wrap|Line Numbers
  1. Matrix& Matrix::operator=(const Matrix& rhs)
  2. {
  3.     iMax = rhs.iMax;
  4.     jMax = rhs.jMax;
  5.     kMax = rhs.kMax;
  6.  
  7.     if (data!= 0)
  8.     {
  9.         delete [] data;
  10.     }
  11.  
  12.     data = new int[iMax * jMax * kMax];
  13.     for (unsigned int ijk = 0; ijk < iMax * jMax * kMax; ijk++)
  14.     {
  15.         data[ijk] = rhs.data[ijk];
  16.     }
  17.  
  18.     return *this;
  19. }
  20.  
  21.  
  22. Matrix Matrix::operator+(const int& rhs) const
  23. {
  24.     Matrix newMat(iMax, jMax, kMax);
  25.  
  26.     for (unsigned int ijk = 0; ijk < iMax * jMax * kMax; ijk++)
  27.     {
  28.         newMat.data[ijk] = data[ijk] + rhs;
  29.     }
  30.  
  31.     return newMat;
  32. }
  33.  
I appreciate any help on this.
Sep 12 '07 #1
6 2233
Banfa
9,065 Expert Mod 8TB
I assume that data is a member of your class that holds the pointer to the matrix data which you appear to allocate from the heap (using new).

In this case it is almost guaranteed that you will require an explicitly written copy constructor and assignment operator.

The default copy constructor does a shallow copy. That is it just copies the values of the members from one object to the other. For an object with allocated memory (like yours) that means that both objects end up pointing to the same allocated data and when one object is deleted and releases the memory it leaves the other object with an invalid pointer. This is likely to cause memory errors or segmentation faults, which is what you are seeing.

In this case (and what your assignment operator does) you require a deep copy. A deep copy is one that has some knowledge of what it is copying and when it comes accross an allocated buffer rather than copying the pointer it allocates a new buffer for the receiving object and copies the data in the buffer not the pointer to the buffer.

As far as I can tell C++ does tend to do these hiden allocations and secret object instatiations. I can't say I like it but that's how it is. Sometimes it is possible to write your code to reduce them, for instance if you are using the increment operator (++) on an object (rather than a built in type) then pre-increment tends to be more efficient than post-increment because post-increment requires that a copy of the current object is taken and returned where as pre-increment can perform the entire operation in the current object and return it. Obviously this is true for decrement.

In place operations also tend to be more efficient due to the reduction of object copying, e.g. a += 1; is more efficient than a = a + 1;
Sep 12 '07 #2
weaknessforcats
9,208 Expert Mod 8TB
The default copy constructor does a shallow copy. That is it just copies the values of the members from one object to the other.
Not quite true. The default copy constructor does memberwise copy. That means a copy constructor call for every member that is a struct/class. Only pointers and the fundamental types have their values copied.

That means a deep copy where copy constructors are called.

I appreciate any help on this.
Your assgnment operators should check for no self-assignment. Otherwise, you will delete the data you are about to assign. You need a check like:

[code=cpp]
Matrix& Matrix::operator=(const Matrix& rhs)
{
if (this == &rhs) return *this; //no self-assignment

iMax = rhs.iMax;
jMax = rhs.jMax;
kMax = rhs.kMax;

if (data!= 0)
{
delete [] data;
}
etc....
}
Sep 12 '07 #3
Banfa,

Thanks for clarifying this. Indeed data is a member of the Matrix class that is a pointer to an array of ints. It is allocated/deallocated using new int[] and delete []. The shallow copy of this pointer clearly explains why I was seeing the behavior I was seeing. What I do not understand is why the compiler feels the need to call the copy constructor to create a new object here rather than just pass the temporary object that is returned from operator+ to the operator= function.

Clearly I am going to have to be pretty careful with how I implement and use the operators for the matrix class to minimize the data allocation and copies. I need to lean hard on the in place operators I guess. Learn something new every day!!

Thanks for the information.
Sep 12 '07 #4
Your assgnment operators should check for no self-assignment. Otherwise, you will delete the data you are about to assign. You need a check like:
Thanks! I had not thought of that. I'd probably have spent a few evenings with the debugger trying to track that down...
Sep 12 '07 #5
weaknessforcats
9,208 Expert Mod 8TB
Look at this code:
Matrix Matrix::operator+(const int& rhs) const
{
Matrix newMat(iMax, jMax, kMax);

for (unsigned int ijk = 0; ijk < iMax * jMax * kMax; ijk++)
{
newMat.data[ijk] = data[ijk] + rhs;
}

return newMat;
}
Here you see newMat created as a local variable in the function. When you return newMat, you cannot return the local variable since it will be destroyed. So, the compiler calls your copy constructor to make an object to return.

This is one reason why copy constructors are so important.
Sep 12 '07 #6
Look at this code:


Here you see newMat created as a local variable in the function. When you return newMat, you cannot return the local variable since it will be destroyed. So, the compiler calls your copy constructor to make an object to return.

This is one reason why copy constructors are so important.
Yeah, I ran across a discussion of this today in an article on optimization. It is pretty obvious now why the call to the copy constructor is required. Unfortunate, but required.

The article I was looking at is, http://www.tantalon.com/pete/cppopt/main.htm. This is a fairly nice article by the way. The discussion of this I was looking at is in the section Final Optimization, "Avoid temporary objects: the return value optimization."

Thanks for the help.
Sep 13 '07 #7

Sign in to post your reply or Sign up for a free account.

Similar topics

11
by: Kurt Krueckeberg | last post by:
Given a class X class X { public: X(int); X(const X&); //. . . }; Is this line X x1(1); the same thing as X x2 = 2;
1
by: Tony Johansson | last post by:
Hello experts! I have this piece of code. No user defined copy constructor exist. AccountForStudent create(long number) { AccountForStudent local(number, 0.0); return local; } int main() {
8
by: Jesper | last post by:
Hi, Does the concept "copy constructor" from c++ excist in c#. What is the syntax. best regards Jesper.
7
by: pauldepstein | last post by:
A book I have describes a class called vector. It then explains (and I understand) the concept of a copy constructor, which is needed to interpret statements like vector b = a; But then I...
10
by: dragoncoder | last post by:
Hi all, I am trying to understanding std::auto_ptr<Tclass implementation from "The C++ standard library" by Nicolai Josuttis. He gives a sample implementation of auto_ptr class template in...
22
by: clicwar | last post by:
A simple program with operator overloading and copy constructor: #include <iostream> #include <string> using namespace std; class Vector { private: float x,y; public: Vector(float u, float...
13
by: JD | last post by:
Hi, My associate has written a copy constructor for a class. Now I need to add an operator = to the class. Is there a way to do it without change her code (copy constructor) at all? Your help...
2
by: sanjay | last post by:
Hi All, I have a doubt in understanding the output of the following program that i executed on my system. I was using DevC++ IDE which uses minGW based compiler. ...
34
by: =?ISO-8859-1?Q?Marcel_M=FCller?= | last post by:
Hi, is there a way to avoid the automatic copy constructor generation. I do not want the object to be non-copyable. I simply do not want that copying is done by the default copy constructor. But...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
0
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.