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.
Related
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.
Say I have a simple struct that contains a vector and defines a copy assignment operator, and a function that returns this struct, like so:
struct SimpleStruct
{
vector< int > vec1;
operator=( SimpleStruct& other )
{
vec1 = other.vec1;
}
}
SimpleStruct GetStruct();
As I understand it, because I've declared a copy assignment operator, the compiler won't automatically generate a move constructor for SimpleStruct.
So if I use the GetStruct function like this:
SimpleStruct value = GetStruct();
Is the compiler smart enough to move rather than copy the vector when I say vec1 = other.vec1;? Or will I need to explicitly define a move constructor/assignment operator for SimpleStruct to take advantage of a vector move?
C++11 has very strict rules about when movement is allowed to happen. And unless a temporary is involved, those rules require the explicit use of std::move or a similar cast (such as std::forward in some cases).
Yes, you could move something. But it wouldn't happen by accident; it would have to be deliberate.
Also, it is generally rude to write a copy-assignment operator that can modify what is being copied. That's why they usually take a const&, which pretty much guarantees the inability to move.
Or will I need to explicitly define a move constructor/assignment operator for SimpleStruct to take advantage of a vector move?
In general, this is why you don't explicitly define copy and move constructors. Let the compiler do it's job and generate those for you (unless you're using VC++ which doesn't do its job for move constructors/assignment). Only explicitly write copy/move constructors for lower-level containers; anything larger should just rely on those value types to do their jobs.
Inside a copy constructor or copy assignment operator, copy means copy. The language never makes any contextual adjustment to the contents of a function based on how it is called.
However, it's likely that no copy will occur in SimpleStruct value = GetStruct(); because copy elision applies.
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.
I'm writing an application, where I want to store strings as keys ans a custom Object as value
multimap<string, owncreatedobject> mymap;
Compiling does well, but I get a "Segmentation fault" when using the function insert
during runtime.
mymap.insert(string,myobject); --> Segmentation Error
A already added a copyconstructor an assignmentfunction (which calls the copyconstructor)
any idea about the "Segmentation fault?
Looking at the comment you added for the copy constructor and assignment operator implementation, I found that your assignment operator implementation is wrong. Basically it is not copying anything, instead with the statement Filter(f); , you are creating a local object named f. You can not call copy constructor like that. I suggest you to write a private copy method and use it in both copy ctor and assignment operator.
I fiddle with your problem for the last hour and I think I got it.
Try using something in the matter of this code segment:
multimap<string,yourclass const*> mymap
void addtomap(string s,yourclass const* c)
{
mymap.insert(pair<string, yourclass const*>(s,c));
}
...`addtomap("abc",&z);
In your given example you tried to insert without an iterator. The first element for a 2 element insert call for a multimap is the iterator. That's the reason for your segmentation fault and why one should use pair.
I suspect that you have a buggy copy constructor and/or assignment operator implementation.
If the line
mymap.insert(std::make_pair(mystring,myobject));
crashes, it's pretty likely that some method which is executed on 'myobject' causes the problem. In this code line, the most interesting functions are the copy constructor and/or the assignment operator.
You say that you already added an assignment operator (which calls the copy constructor), but that sounds strange. Usually it's exactly the other way round; the copy constructor allocates resources (i.e. memory) as needed and then calls the assignment operator.
UPDATE: After reading your comment, here's how your copy constructor should look like:
Filter::Filter( const Filter &rhs ) {
// Apparently no resource acquisition like memory allocation is necessary,
// so just assign the rhs value.
*this = rhs;
}
And here's the assignment operator. Note how it just copies over the values. Chances are that you don't need an assignment operator (or copy constructor) implementation at all because the compiler-synthesized code is fine for your uses.
Filter &Filter::operator=( const Filter &rhs ) {
SrcNET = f.SrcNET;
SrcPort = f.SrcPort;
DstNET = f.DstNET;
FlowLabel = f.FlowLabel;
return *this;
}
I assume you're trying to call the insert version that accepts a value_type of the multimap. In this case, just remember that multimap's value_type is a std::pair. Then, try this:
mymap.insert(std::make_pair(mystring,myobject));
EDIT (after your comment): Your assignment operator contains an error. You create a temporary that serves for no purpose. Below is a suggestion of implementation using the swap idiom. (Notice that I don't know what are the types of the class member. Suppose they're a builtin such as int for example.)
void Swap(Filter const& f) //Create a swap member function.
{
std::swap(SrcNET, f.SrcNET);
std::swap(SrcPort, f.SrcPort);
std::swap(DstNET, f.DstNET);
std::swap(DstPort, f.DstPort);
std::swap(FlowLabel, f.FlowLabel);
}
Filter& Filter::operator =(Filter f)
{
swap(f); //Swaps the copy created for parameter passing (pass-by-value) above.
return *this;
}