I've been scratching my head all day new to operator overloading and my operator+ function computes the data correctly, but I need to pass the data of temp class to operator= to assign it to a separate instance of my class and returning temp does not work (I imagine the data is being destroyed on exit?)
the whole idea is from main x = y + z is called to add the data of two vectors from y and z and asign it to x and I get the computation of y + z correctly, but passing it to x I've hit a brick wall what is wrong? or does anyone have idea?
This is piece my code from my class
VecXd& operator=(const VecXd& rhs)
{
VecXd<V> temp;
temp.dimension = rhs.dimension;
cout << "operator= check dimension is..." << temp.dimension << endl;
for(int i = 0; i < rhs.dimension; i++) //Passing data to x?
{
cout << "test" << endl;
temp.vecArr[i] = rhs.vecArr[i];
cout << temp.vecArr[i] << " our new value" << endl;
}
}
friend VecXd& operator+(VecXd& lhs, VecXd& rhs){
VecXd<V> temp;
cout << lhs.dimension << "-lhs d-" << rhs.dimension << "-rhs d-" << endl; //works
if(lhs.dimension == rhs.dimension) //dimension level check
{
temp.vecArr = new V[lhs.dimension];
for(int i = 0; i < lhs.dimension; i++)
{
temp.vecArr[i] = lhs.vecArr[i] + rhs.vecArr[i];
cout << temp.vecArr[i] << " our new value" << endl;
}
//return *temp.vecArr;
return temp; //***? how to pass data?
}
else{
cout << "Dimensions do not match!!! Error!" << endl;
}
}
any idea? don't be to harsh... haha..... :l
Your assignment operator is bogus: the operation the assignment is supposed to do is to make the object pointed to by this the same as the object on the right hand side. Your assignment operator creates a temporary object and sets this object up. However, it goes away when exiting the assignment operator. Also, you declared your assignment operator to return a reference which conventionally returns a reference to *this but there is no return
statement.
Unless I have a very good reason to do it differently, I implement my assignment operator in terms of the copy constructor, the destructor, and a swap() function:
VecXd& VecXd::operator=(VecXd rhs)
{
this->swap(rhs);
return *this;
}
The copy constructor is called to create the argument to function, nicely copying the object. Then the newly created copy is exchanged with the content of the object being assigned to and, after returning *this the original content is released by the destructor of the temporary object created for rhs. All what is required is a relatively function swap():
void VecXd::swap(VecXd& other)
{
std::swap(this->dimension, other.dimension);
std::swap(this->vecArr, other.vecArr);
}
The swap() function assumes that the two members can be swapped, of course. Since I haven't seen your declaration of VecXd I can't tell whether this would work but it should generally work.
I haven't really looked at your addition operator.
This Caltech C++ Operator Overloading Page should have everything you need and a relatively clear explanation of the logic involved. It is not by any means required that you follow the rules and guidelines laid out there, but they work well in the general case.
In the specific case of the arithmetic operators, the operation is often defined in terms of the += operator, as noted in the comment on your original post by chris. This means that you typically pass in the right and left arguments, make a copy of lhs, and find the result by using lhs_copy += rhs; it's easier to avoid code duplication with this in mind; you'll only be creating the addition logic once in += and then calling it in +.
The result you return cannot be a reference - nothing created in the function will persist, but neither the lhs or rhs arguments should be changed. Instead, you simply return the duplicate lhs you incremented as an instance - in your case the function signature is:
const VecXd operator+(const VecXd& lhs, const VecXd& rhs).
Your input can and should be const since neither item will be changed in the function, and the Caltech page recommends the return type be a const instance to disallow certain odd operations, which again is good practice in many cases.
Related
Consider a class with just a single member for this example.
class tester
{
public:
int tester_value;
tester(){}
tester(int test_val)
{
tester_value = test_val;
}
tester(const tester & data) : tester_value(data.tester_value)
{
std::cout << "Copied!" << std::endl;
}
};
I was curious as to the proper way to overload the = operator and why one way works and another does not.
For example, this operator overload does not seem to properly copy the data from one object to another.
Example 1:
tester operator=(const tester & data) const
{
tester temp;
std::memcpy(&temp, &data, sizeof(tester));
return temp;
}
However, this example works just fine.
Example 2:
tester& operator=(const tester & data)
{
tester_value = data.tester_value;
return *this;
}
When using the following code to test each example...
tester my_test = tester(15);
tester my_second_test = tester(20);
my_test = my_second_test;
std::cout << "my_test.tester_value:" << my_test.tester_value << std::endl;
std::cout << "my_second_test.tester_value:" << my_second_test.tester_value << std::endl;
The result for example 1 will be:
15
20
While the result for example 2 will be:
20
20
So,
Question 1: Why is it that using a temporary variable and memcpy() does not work properly to copy the data from one object to another when overloading the = operator?
Question 2: What is the proper and most efficient way to do overload this operator?
I appreciate any explanation, I am still getting used to the C++ language.
Thanks in advance!
Question 1: Why is it that using a temporary variable and memcpy() does not
work properly to copy the data from one object to another?
This is because of the Golden Rule Of Computer Programming: "Your computer always does exactly what you tell it to do, instead of what you want it to do".
Tester A, B;
// ... at some point later.
A=B;
The instruction A=B instructs your computer to invoke A's operator= overload. In the overload, *this becomes A.
tester operator=(const tester & data) const
{
tester temp;
std::memcpy(&temp, &data, sizeof(tester));
return temp;
}
Nothing here tells your computer that anything in *this gets modified. Since you did not tell your computer to modify this->tester_value it does not get modified.
Nothing here effectively sets A.tester_value. Instead, some new object gets created and returned. That's what you told your computer to do, so that's what it does, no more no less. But the return value is not used for anything. The return value here is the value for the entire A=B; statement itself, which is not used for anything. It is the operator= itself that's responsible for assigning the new value of this object. It is not the return value from the operator= method that sets the new value of the object, it's the operator itself. In the operator= overload, what's on the right side of the = in the expression gets passed to operator= as a parameter, and what's on the left side of the = in the expression is *this.
Question 2: What is the proper and most efficient way to do overload this
operator?
That's already answered by Stackoverflow's canonical on operating overloading. TLDR: it's "Example 2".
I wanted to ask a question about operator overloading in C++.
I am a beginner in C++ and have been learning OOP.
Consider the following overloaded copy assignment operator:
class Base {
private:
int value;
public:
Base () : value {0}
{
cout << "Base No-args constructor" << endl;
}
Base (int x) : value {x} {
cout << "Base (int) overloaded constructor" << endl;
}
Base (const Base &other) : value {other.value} {
cout << "Base copy constructor" << endl;
}
Base & operator = (const Base &rhs) {
cout << "Base operator=" << endl;
if (this == &rhs)
return *this;
value = rhs.value;
return *this;
}
~ Base () {cout << "Base Destructor" << endl;}
};
I wanted to clarify two points.
How does this copy assignment operator work?
Does the reference before the operator keyword need a parameter name?
I wanted to give my interpretation on (1).
If I have the following code in my main():
Base b {100}; // overloaded constructor
Base b1 {b}; // copy constructor
b = b1; // copy assignment
What I think happens is that the no args constructor is called for a1, evidently because no arguments are passed into the construction of the object.
When a2 is initialised, a temporary copy of a1 is made and then the operator is evaluated with respect to the Base class, hence the Base overloaded copy assignment block is run, and the a1 object is returned via return *this to the reference a2.
To explain my thoughts on the second question,
I thought that all parameters need a name when a function or method is declared (I may of course be wrong).
If my overloaded copy assignment block was written hypothetically as:
Base &lhs operator = (const Base &rhs)
am I right in saying that lhs is referring to a2 but as we don't do anything with lhs due to the implied this parameter, we don't need to give a parameter name following the ampersand before the operator?
How does this copy assignment operator work?
Redacted:
Base& operator=(Base const& rhs) {
cout << "Base operator=\n";
value = rhs.value;
return *this;
}
The assignment operator is just a function call. In this particular class's case, the compiler will synthesize one that does the right thing, but if you want the cout side-effect for educational purposes you've done the right thing.
You could also call it in a method function style:
b.operator=(b1);
The b = b1; is just syntactic sugar for the above.
The assignment operator should be self-assignment safe. But general guidance is to make it safe without checking for the self-assignment case explicitly, which is "bad" because it optimizes for the pathological case.
In your implementation, it is safe without the self-assignment check.
I prefer specifying the qualifier in Base const& order rather than const Base& order, because the general rule is "the qualifier always binds to the thing to its immediate left", and the exception to the general rule is "...unless the qualifier comes first, in which case it then binds to the thing to its immediate right." That becomes a problem when people have the grasped the exception to the rule, but not the general rule, and then have troubles parsing Base*const* in their heads.
Does the reference before the operator keyword need a parameter name?
It's name is *this. It is a return type, not a parameter, so it does not have a parameter name.
Some people have troubles with "Why does C++ use this as a pointer to itself, rather than as a reference to itself."
It is a historical anomaly from the evolution of C++. Originally, there was a this pointer, and references had not been added to the language yet.
With 20/20 hindsight, this would have been a reference. But that ship has sailed.
In my own code, only to help make it more legible, I'll do:
auto& self = *this;
self[i] = 5;
...rather than the more confusing (imo)...
(*this)[i] = 5;
In an already existing class of a project I am working on I encountered some strange piece of code: The assignment operator calls the copy constructor.
I added some code and now the assignment operator seems to cause trouble.
It is working fine though if I just use the assignment operator generated by the compiler instead. So I found a solution, but I'm still curious to find out the reason why this isn't working.
Since the original code is thousands of lines I created a simpler example for you to look at.
#include <iostream>
#include <vector>
class Example {
private:
int pValue;
public:
Example(int iValue=0)
{
pValue = iValue;
}
Example(const Example &eSource)
{
pValue = eSource.pValue;
}
Example operator= (const Example &eSource)
{
Example tmp(eSource);
return tmp;
}
int getValue()
{
return pValue;
}
};
int main ()
{
std::vector<Example> myvector;
for (int i=1; i<=8; i++) myvector.push_back(Example(i));
std::cout << "myvector contains:";
for (unsigned i=0; i<myvector.size(); ++i)
std::cout << ' ' << myvector[i].getValue();
std::cout << '\n';
myvector.erase (myvector.begin(),myvector.begin()+3);
std::cout << "myvector contains:";
for (unsigned i=0; i<myvector.size(); ++i)
std::cout << ' ' << myvector[i].getValue();
std::cout << '\n';
return 0;
}
The output is
myvector contains: 1 2 3 4 5
but it should be (an in fact is, if I just use the compiler-generated assignment operator)
myvector contains: 4 5 6 7 8
Your operator= does not do what everyone (including the standard library) thinks it should be doing. It doesn't modify *this at all - it just creates a new copy and returns it.
It's normal to re-use the copy constructor in the copy assignment operator using the copy-and-swap idiom:
Example& operator= (Example eSource)
{
swap(eSource);
return *this;
}
Notice how the operator takes its parameter by value. This means the copy-constructor will be called to construct the parameter, and you can then just swap with that copy, effectively assigning to *this.
Also note that it's expected from operator= to return by reference; when overloading operators, always follow the expected conventions. Even more, the standard actually requires the assignment operator of a CopyAssignable or MoveAssignable type to return a non-const reference (C++11 [moveassignable] and [copyassignable]); so to correctly use the class with the standard library, it has to comply.
Of course, it requires you to implement a swap() function in your class:
void swap(Example &other)
{
using std::swap;
swap(pValue, other.pValue);
}
The function should not raise exceptions (thanks #JamesKanze for mentioning this), no to compromise the exception safety of the operator=.
Also note that you should use the compiler-generated default constructors and assignment operators whenever you can; they can never get out of sync with the class's contents. In your case, there's no reason to provide the custom ones (but I assume the class is a simplified version for posting here).
The assignment operator you found is not correct. All it does is make a copy of eSource, but it's supposed to modify the object on which it is called.
The compiler-generated assignment operator for the class is equivalent to:
Example &operator= (const Example &eSource)
{
pValue = eSource.pValue;
return *this;
}
For this class there's no point implementing operator=, since the compiler-generated version basically cannot be improved on. But if you do implement it, that's the behaviour you want even if you write it differently.
[Alf will say return void, most C++ programmers will say return a reference. Regardless of what you return, the vital behaviour is an assignment to pValue of the value from eSource.pValue. Because that's what the copy assignment operator does: copy from the source to the destination.]
First of all, operator=() should return a reference:
Example& operator=(const Example& eSource)
{
pValue = eSource.pValue;
return *this;
}
Mind that your version returns a copy of tmp so in fact it performs two copies.
Second of all, in your class there's no need to even define custom assignment operator or copy constructor. The ones generated by compiler should be fine.
And third of all, you might be interested in copy-and-swap idiom: What is the copy-and-swap idiom?
Probably the most frequent correct implementation of operator=
will use the copy constructor; you don’t want to write the same
code twice. It will do something like:
Example& Example::operator=( Example const& other )
{
Example tmp( other );
swap( tmp );
return *this;
}
The key here is having a swap member function which swaps the
internal representation, while guaranteeing not to throw.
Just creating a temporary using the copy constructor is not
enough. And a correctly written assignment operator will always
return a reference, and will return *this.
I'm trying to make me clear about move semantics. I'm following examples of the Bjarne Stroustrup book 4th edition and I'm really lost.
He says that copy of objects can be expensive when a lot of elements (in class vector) so move semantics is the solution.
Think something like:
Vector result = vector1 + vector2 + vector3;
Order may be wrong but it will do (vector2 + vector3) generating partial result result1, and result1 + vector1, generating result;
I overloaded operator+:
Vector operator+(const Vector &a,const Vector &b)
{
if(a.size()!=b.size()) {
throw length_error{"Length of vectors must match for summing"};
}
Vector result(a.size());
cout << "Intermediate result for sum created" << endl;
for(long unsigned int i=0; i<result.size();i++){
result[i] = a[i] + b[i];
}
return result;
}
I also created a move constructor:
Vector::Vector(Vector&& orig) noexcept
:elem{orig.elem},
sz{orig.sz}
{
cout << "Move constructor called" << endl;
orig.elem = nullptr; // We own the array now
orig.sz = 0;
}
So no copy operations are performed. But there are some things I don't understand. One is related to just c++ and the other to c++11.
So first:
As you can see, when operator+ exits Vector result should be destroyed. But not after the contents are copied to another instance of vector. What I called partial result1.
This never happens, the output of the program is like this:
New class vector created <-- Constructor of partial result 1
Intermediate result for sum created <-- Operator+ applied
New class vector created <-- Constructor of partial result 2 -> goes to result
Intermediate result for sum created <-- Operator+ applied
Class vector destroyed <-- I undenderstand that partial result 1 destroyed.
But I don't see the second partial result destroyed until the end of the program. Nor I see any copy operations (I have done operator= and copy constructor).
So I don't understand that. If the scope of the variable Vector result is inside operator+ the contents MUST be copied to another variable. That's not done. It seems that last result of the sum is just assigned to Vector result of the sum.
Second:
No move operations are performed. I cannot get move semantics to work here. I took a look to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52745 and applied what's there but no move operations anyway.
Every result is right.
So clearly, there is something I'm doing wrong.
You can grab the whole code (with autotools config + eclipse) from here:
http://static.level2crm.com/cx11-learn-20140218.tar.bz2
Can someone explain what happens here?
Best regards,
First and foremost, there is no move-construction here. There is NRVO occurring (as per comments on your question) but if you want to testify of move-construction occurring, you should try to copy a temporary. Try re-implementing your operator as follows:
// Note that the first parameter is taken by value.
Vector operator+(Vector a, const Vector &b)
{
cout << "Intermediate result for sum created or moved from a" << endl;
// NOTE: Could be implemented as operator+= and written a += b.
if(a.size()!=b.size()) {
throw length_error{"Length of vectors must match for summing"};
}
for(long unsigned int i=0; i<a.size();i++){
a[i] += b[i];
}
// END NOTE
return a;
}
Note that your operator now requires a local "copy" as first parameter. On the first sum, since a Vector& will be provided as argument (the object has a name), the copy constructor will be called and create an object with a new buffer (what you are doing with your result local variable). Then, a temporary will be formed, so on the second call to your operator+, a Vector&& will be provided as first argument and the move-constructor will be called, effectively stealing the buffer of the temporary.
If you prevent constructor elision as per comments, you should be able to see some move constructors called.
EDIT: A more detailed explanation of why you won't have a move in your case. The short version is that C++ does not do magic :)
The aim of a move in the case of chained additions is to avoid repeatedly creatingthe buffers of your Vectors due to the creation of temporaries. Instead of losing the buffers to the destruction of the temporaries, the aim is to reuse the buffer of the temporary to store the result.
In your case, you're not even trying to copy the buffer of the Vector. You're explicitly creating a new buffer on this line:
Vector result(a.size());
You're saying "Please create a vector of the right size for the result", and doing it once for every addition. You had better say "Please steal the buffer of a" if you know that a will die soon. It is written:
Vector result(a);
But for this to work, a must refer to an object that will die soon, and this means a must be of type Vector&&. When this is done, result already contains the values of a, so all you have to do is add the values of the elements of b.
for(long unsigned int i=0; i<result.size();i++){
result[i] += b[i];
}
(Expressing + in terms of += is idiomatic)
So to testify of move construction, you should have a definition of your operator+ whose signature is:
Vector operator+(Vector&& a, const Vector &b) {
if(a.size()!=b.size()) {
throw length_error{"Length of vectors must match for summing"};
}
Vector result(a);
cout << "Intermediate result for sum moved from a" << endl;
for(long unsigned int i=0; i<result.size();i++){
result[i] += b[i];
}
return result;
}
But this won't work with the first addition, since it is not adding a temporary to another named object, but two named objects. You should have an overload of your operator+ that copes with lvalue references:
Vector operator+(const Vector& a, const Vector &b) {
if(a.size()!=b.size()) {
throw length_error{"Length of vectors must match for summing"};
}
Vector result(a); // In this case, this is a copy
cout << "Intermediate result for sum created" << endl;
for(long unsigned int i=0; i<result.size();i++){
result[i] += b[i];
}
return result;
}
Notice that both versions share the same text. Which brings to another idiomatic way of doing: letting the compiler decide of whether to do the move or the copy by requiring the left side of operator+ to be passed by value, requiring only one overload. (This is the version at the beginning of my answer.
I made the following operator overloading test:
#include <iostream>
#include <string>
using namespace std;
class TestClass
{
string ClassName;
public:
TestClass(string Name)
{
ClassName = Name;
cout << ClassName << " constructed." << endl;
}
~TestClass()
{
cout << ClassName << " destructed." << endl;
}
void operator=(TestClass Other)
{
cout << ClassName << " in operator=" << endl;
cout << "The address of the other class is " << &Other << "." << endl;
}
};
int main()
{
TestClass FirstInstance("FirstInstance");
TestClass SecondInstance("SecondInstance");
FirstInstance = SecondInstance;
SecondInstance = FirstInstance;
return 0;
}
The assignment operator behaves as-expected, outputting the address of the other instance.
Now, how would I actually assign something from the other instance? For example, something like this:
void operator=(TestClass Other)
{
ClassName = Other.ClassName;
}
The code you've shown would do it. No one would consider it to be a particularly good implementation, though.
This conforms to what is expected of an assignment operator:
TestClass& operator=(TestClass other)
{
using std::swap;
swap(ClassName, other.ClassName);
// repeat for other member variables;
return *this;
}
BTW, you talk about "other class", but you have only one class, and multiple instances of that class.
The traditional canonical form of the assignment operator looks like this:
TestClass& operator=(const TestClass& Other);
(you don't want to invoke the copy constructor for assignment, too) and it returns a reference to *this.
A naive implementation would assign each data member individually:
TestClass& operator=(const TestClass& Other)
{
ClassName = Other.ClassName;
return *this;
}
(Note that this is exactly what the compiler-generated assignment operator would do, so it's pretty useless to overload it. I take it that this is for exercising, though.)
A better approach would be to employ the Copy-And-Swap idiom. (If you find GMan's answer too overwhelming, try mine, which is less exhaustive. :)) Note that C&S employs the copy constructor and destructor to do assignment and therefore requires the object to be passed per copy, as you had in your question:
TestClass& operator=(TestClass Other)
almost all said, a few notes:
check for self-assignment, i.e. if (&other != this) // assign
look here for an excellent guide on operator overloading
Traditionnaly the assignment operator and the copy constructor are defined passing a const reference, and not with a copy by value mechanism.
class TestClass
{
public:
//...
TestClass& operator=(const TestClass& Other)
{
m_ClassName= Other.m_ClassName;
return *this;
}
private:
std::string m_ClassName;
}
EDIT: I corrected because I had put code that didnt return the TestClass& (c.f. #sbi 's answer)
You are correct about how to copy the contents from the other class. Simple objects can just be assigned using operator=.
However, be wary of cases where TestClass contains pointer members -- if you just assign the pointer using operator=, then both objects will have pointers pointing to the same memory, which may not be what you want. You may instead need to make sure you allocate some new memory and copy the pointed-to data into it so both objects have their own copy of the data. Remember you also need to properly deallocate the memory already pointed to by the assigned-to object before allocating a new block for the copied data.
By the way, you should probably declare your operator= like this:
TestClass & operator=(const TestClass & Other)
{
ClassName = Other.ClassName;
return *this;
}
This is the general convention used when overloading operator=. The return statement allows chaining of assignments (like a = b = c) and passing the parameter by const reference avoids copying Other on its way into the function call.