Basically, is it acceptable programming practice/style to call a constructor of a class within its overloaded assignment operator? If not, why not?
EXAMPLE:
so I have a class which has 3 data members, a dynamic int array called "value" which holds digits of a large number, an int length which indicates the number of digits in the number, & an int maxLength which indicates the max length of the number (size of the dynamic array)
here's my constructor with param int:
bigInt::bigInt(const int &rhs){
//turn num_ into a string 'num'
stringstream ss;
ss << num_;
string num = ss.str();
length = strlen(num.c_str());
maxLength = (length - (length%16)) + 16;
value = new int[maxLength];
for(int i=1; i<=length; i++){
value[i-1] = num.at(length-i) - '0';
}
}
and here's my overloaded assignment operator in which the righthand side is a regular int
this method calls the constructor:
bigInt bigInt::operator=(const int &rhs){
*this = bigInt(rhs);
return *this;
}
EDIT: I guess I should have worded it differently. I didn't mean COPY constructor, but rather a regular constructor with non-class-instance parameter, and an overloaded assignment operator in which the rhs isn't the same type as the lys
There's nothing wrong with calling the copy constructor in the
implementation of an assignment operator (unless the copy
constructor itself is implemented in terms of assignment, of
course). In fact, it's a common idiom: make a local copy, then
swap the data with the current instance. (This, of course,
supposes that you have a specialized swap. Just calling
std::swap on the object itself in an assignment operator is
not a good idea. Creating a new instance, and then swapping
the individual components of the object often is. Or creating
a custom swap function which swaps the components, and calling
it.)
This is not an unreasonable way to implement your assignment operator, since it allows you to utilize existing code, and provides the strong guarantee as long as your copy assignment operator does.
Two points of note however: First, make sure that your copy constructor, copy assignment operator, and destructor are all implemented properly or you'll start having memory management problems. Second, the C++ language ALREADY provides a class with elements, a length, and a max length: It's called std::vector and if you change your code to use it, you don't need to write the copy constructor, copy assignment operator, and destructor at all, as they'll just behave properly!
Also, your assignment operator should return by reference (or if you really don't want chaining, void). Returning by value will someday cause a bug when a chained assignment doesn't work as expected.
The opposite is better. It's perfectly fine.
However, don't forget that in the copy contructor you MUST redo what you do in the constructor; i.e., initialize any variables you have in your class, which is not necessary to be done in the overloaded assignment operator function.
Related
In this piece of code below, I am having std::map in a structure. And I am then just assigning an instance of the structure to other. Note that the structure doesn't have assignment operator. In this case shall I expect assignment operator of map would be called or compiler just shallow copies memory contains of structures ?
int _tmain(int argc, _TCHAR* argv[])
{
struct vectstruct
{
std::map<int, double> mymap;
};
vectstruct vs1, vs2;
vs1.mymap[7] = 54.321;
vs2 = vs1; // Should call assignment operator of map vs2.mymap
vs1.mymap[7] = 65.432;
return 0;
}
I tried this with Microsft Visual Studio and at the end of program I see value of vs2.mymap[7] remains 54.321 as expected. But I like to know is it correct by C++ standards or do I need to write assignment operator of vectstruct wherein I explicitly would invoke assignment operator of map?
As a matter of style, you should declare and define your types outside of main.
That said, if you do not provide a copy assignment operator, the compiler will implicitly create* one for you and that implicit one will just do an element-wise copy assignment. In this case, the implicit one will look something like:
vectstruct& operator=(const vectstruct& rhs) {
mymap = rhs.mymap;
return *this;
}
For std::map, assignment does full copy, it doesn't take a reference, so at the end of your code you should expect:
vs2.mymap[7] == 54.321 // to the extent that equality of doubles is a thing
vs1.mymap[7] == 65.432
*There are cases when the compiler cannot create an implicit assignment operator which basically boil down to your object having a noncopyable member. For instance, a reference, or a unique_ptr.
The default operator= will perform a member-by-member copy, which is what you expect. I. e. it will invoke operator= for every data member of your struct. And std::map, in turn, implements operator=, so everything will work like charm. No need to bloat your code by writing the same operator yourself.
I'm just a beginner in the C++ language and I have some questions on this piece of code. I am trying to overload some operators.
string& operator = (char R) { string T = R ; *this = T; return *this; }
First Question: Why I need to overload the equal operator while the constructor can do the job?
Second Question: (Not Related) What does (char R) means?
First Question: Why I need to overload the equal operator while the constructor can do the job?
The constructor is designed to "construct" an object ... while there is something called a copy-constructor, it is not designed to actually copy an already existing object into another already existing object of the same (or convertable) type ... that is the job of the operator=. Also you are not "overloading" the operator= method, but rather creating a user-defined version of the method to be used instead of the default compiler-created method for the object type which would simply brute-force copy the bits of the memory footprint of one object into another ... if your object is managing it's own pointers, etc., such a brute-force copy can be a very bad thing as pointer ownership becomes ambiguous, etc.
(char R) is the right-side argument of the operator (here =)
You want to do that so you can set a value after initialization
//constructor
Foo a('f')
//copy constructor
Foo b = Foo('p');
// operator=
b = 'g';
(char R) is the argument to the operator just like you have an argument to a normal function.
Operator overloading in C++ . One of best version here.
http://msumca2012.blogspot.in/2013/03/oop-41-operator-overloading-in-c.html
Here is my code:
class Example {
...declarations/definitions...
};
Example operator + (Example e)
{
Example temp;
...do addition...
return temp;
}
//main
void main()
{
Example a(1,2);
Example b(3,4);
Example c;
c = a+b;
}
Now what confuses me is that I had to overload the + operator for it to work with the vectors but how about the equal '=' sign?? I am assigning one vector to another, shouldn't i be overloading it too?? Or is it provided already to us?
Thanks.
The language provides a default operator= for you automatically if your class is default assignable (for example if it has any reference members it won't be assignable without special work by you). All it does is assign the base and each member individually.
From the wikipedia page:
The default version [of the assignment operator] performs a memberwise copy, where each member is copied by its own copy assignment operator (which may also be programmer-declared or compiler-generated).
If you don't declare a copy-assignment operator in your class, then one is implicitly declared for you (and implicitly defined if you ever use it).
The implicit operator will assign each member of your object, if that's possible; otherwise (if some member is a reference, or const, or has a private or deleted copy-assignment operator) you'll get a compile error.
Similarly, if you don't declare a copy constructor, then you'll get an implicit one, which will copy each member. Your code is using that in operator+, to copy both the argument and the return value.
The assignment operator is given by default, along with the copy constructor, and default constructor. It assigns the value of each data member to its corresponding data member in the other object (i.e., shallow copy).
A std::vector? If so, std::vector implements the assignment operator by default. From the manpage:
"Assigns a copy of vector x as the new content for the vector object.
The elements contained in the vector object before the call are dropped, and replaced by copies of those in vector x, if any.
After a call to this member function, both the vector object and vector x will have the same size and compare equal to each other."
edit-one of these days I'm going to submit an answer first!
C++ provides a default copy constructor for you that is used for assignment, it copies the class member by member using their (also possibly default) copy constructors.
I read about this from "Effective c++" ,this is Col.10.
It say it's a good way to have assignment operators return a reference to *this.
I wrote a code snippet to test this idea. I overridden the assignment operator here.And tested it. Everything is fine.
But when I remove that operator overriding, everything is the same. That means, the chaining assignment still works well. So, what am I missing? Why is that? Need some explanation from you guys, THank you.
#include <iostream>
using namespace std;
class Widget{
public:
Widget& operator=(int rhs)
{
return *this;
}
int value;
};
int main()
{
Widget mywidget;
mywidget.value = 1;
Widget mywidget2;
mywidget2.value = 2;
Widget mywidget3 ;
mywidget3.value = 3;
mywidget = mywidget2 = mywidget3;
cout << mywidget.value<<endl;
cout << mywidget2.value<<endl;
cout << mywidget3.value<<endl;
}
If you remove completely the operator= method, a default operator= will be created by the compiler, which implements shallow copy1 and returns a reference to *this.
Incidentally, when you write
mywidget = mywidget2 = mywidget3;
you're actually calling this default operator=, since your overloaded operator is designed to work with ints on the right side.
The chained assignment will stop working, instead, if you return, for example, a value, a const reference (=>you'll get compilation errors) or a reference to something different from *this (counterintuitive stuff will start to happen).
Partially related: the copy and swap idiom, i.e. the perfect way to write an assignment operator. Strongly advised read if you need to write an operator=
The default operator= will perform as if there were an assignment between each member of the left hand operand and each member of the right hand one. This means that for primitive types it will be a "brutal" bitwise copy, which in 90% of cases isn't ok for pointers to owned resources.
The question touches two different concepts, whether you should define operator= and whether in doing so you should return a reference to the object.
You should consider the rule of the three: if you define one of copy constructor, assignment operator or destructor you should define the three of them. The rationale around that rule is that if you need to provide a destructor it means that you are managing a resource, and in doing so, chances are that the default copy constructor and assignment operator won't cut it. As an example, if you hold memory through a raw pointer, then you need to release the memory in the destructor. If you don't provide the copy constructor and assignment operator, then the pointer will be copied and two different objects will try to release the memory held by the pointer.
While a pointer is the most common example, this applies to any resource. The exception is classes where you disable copy construction and assignment --but then again you are somehow defining them to be disabled.
On the second part of the question, or whether you should return a reference to the object, you should. The reason, as with all other operator overloads is that it is usually a good advice to mimic what the existing operators for basic types do. This is sometimes given by a quote: when overloading operators, do as ints do.
Widget& operator=(int rhs)
This allows you to assign an int to a Widget - e.g. mywidget = 3;
Make a Widget& operator=(Widget const & rhs) - it'll be called for your mywidget = mywidget2 = mywidget3; line.
You do not need an operator=(Widget const & rhs) though - the default should do fine.
Also, it may be a good idea to add e.g. cout << "operator=(int rhs)\n"; to your custom operator - then you'd see that it didn't get called at all in your code.
ostream& operator<<(ostream& out, const hashmap& h)
{
const char *getSymbol = NULL;
h.hashTable->displayHeaders(out);
for ( int hashIndex = 0; hashIndex < maxSize; hashIndex++ )
{
getSymbol = h.hashTable[hashIndex].getSymbol();
if ( getSymbol )
{
out << h.hashTable[hashIndex];
}
}
return out;
}
If I read the code right as the formatting is somewhat off, the problem is most likely that your stock copy constructor does a shallow copy whereas the assignment operator for the same class makes a deep copy. From reading the rest of the code, I assume you meant to make a deep copy instead of just duplicating the m_name and m_symbol pointers.
I'd also strongly suggest that you use std::string instead of raw char pointers - doing that in the first place would have avoided the issues I describe above. It would've also allowed you to use the compiler generate copy constructor, assignment operator and destructor. Less code is good.
Something went wrong with the formatting when you posted your code, so I had to move it to an external editor to read.
The problem is not a memory leak - that would be memory that you failed to reclaim. This is quite the opposite issue. Here, you are trying to reclaim memory that was already freed.
I would bet anything that the failing delete call in the destructor is occuring on an object that was either copied or populated using either the copy constructor or the second overloaded assignment operator. You are performing a shallow copy in those places, resulting in two stock objects referencing exactly the same memory for their mname and msymbol members. Whichever one of the two (or more if you copied many times) is destroyed first will have no problems. Whichever one is destroyed second will fail.
I also make the following observation: your constructor carefully checks symbol and name to see if they actually reference any data. Only then do you proceed to use their values. If they are null, then you assign a value of null to the corresponding members. The first overloaded assignment operator, on the other hand, is copying an instance of stock that for all you know could have null mname or msymbol members. You should treat those values with the same care you did in the constructor and test them before using.
The problem is here:
stock& stock::operator=(stock const * const s)
Look at the logic of this operator and the other assignment operator you declared: you copy m_symbol and m_name differently!
You would be better off defining the assignment operator only once:
stock& stock::operator=(stock const * const s)
{
return this->operator=(*s);
}
Or the other way around if you prefer, but remember that the implementation of this one is off.