I have class foo that manages a vector of floats of fixed length and some metadata. I have implemented a naive overload for operator*:
constexpr int numOfElements = 9;
class foo {
public:
foo()
: x(0), y(0), data(numOfElements)
{}
foo operator*(float value) {
foo result;
for (size_t k = 0; k < this->data.size(); ++k)
result.data[k] = this->data[k] * value;
return result;
}
int x;
int y;
std::vector<float> data;
};
later, I use it in the following way:
some_foo = *ptr_to_another_foo * 5;
where some_foo and ptr_to_another_foo were defined elsewhere and hold some values. This computes the correct result. However, result foo in the overloaded operator creates another object which causes memory allocation which is unacceptable due to performance reasons. Since some_foo already has memory allocated for data, is there a way to implement the overloaded operator in such a way that some_foo.datas memory will be used instead of allocating the temporary foo result?
I could always implement a C-like pointer-based multiplication function, but I would like to do something more idiomatic in C++.
Write a operator*= that multiplies the elements in place:
foo& operator*=(float value) {
for (size_t k = 0; k < this->data.size(); ++k)
this->data[k] *= value;
return *this;
}
If later you realize that you do need also operator* you can implement it in terms of operator*=:
foo operator*(float value) const {
foo result = *this;
result *= value;
return result;
}
Note that operator* is expected to return a new object and not modify this (it should be a const method), while operator*= is expected to return a reference to *this (after modifying it). If you want to make the operation in place, better use the compound *=.
Do not return a foo. Instead, return a wrapper object which refers to *this and can be used as operand for assignment into another foo, changing its state with the multiplied values. This has the caveat that the returned wrapper becomes invalid in case the referred foo is destroyed.
A general pattern for this idea is called expression templates. This is commonly used in linear algebra libraries.
Related
template <typename T>
void myswap(T a,T b)
{
T temp = a;
a = b;
b = temp;
}
int main()
{
int m(20),n(30);
myswap(ref(m),ref(n));
//m is still 20 and n is still 30
}
Why have not the values of m and n interchanged? Passing a value wrapped in std::ref to an INCREMENT function results in value change in the original variable (variable in the stack frame that calls INCREMENT function). Or, Is std::ref usage is restricted/limited?
std::ref (and its associated std::reference_wrapper) is a tool designed for very specific use cases in the standard library and should only be used for those; if you want to use it in your own places, you have to understand it in detail and respect what it does.
Fundamentally, a reference_wrapper is much closer to a pointer than a reference. So substitute a pointer in your swap function and you'll see that there's no reason to assume that it would actually swap:
void myswap(int* a, int* b)
{
int* temp = a;
a = b;
b = temp;
}
Your code creates two temporary std::reference_wrapper objects and swaps them, so they refer to different objects. All that happens is you swap two reference_wrapper objects, not their targets.
If you manually write what the function template will generate the reason for the behaviour should be obvious:
void myswap(std::reference_wrapper<int> a, std::reference_wrapper<int> b)
{
std::reference_wrapper<int> temp = a;
a = b;
b = a;
}
Obviously this doesn't change the int objects, only the reference_wrapper objects.
If what you're trying to do is force myswap to take references you need to call myswap<int&>(m, n), you can't emulate that by using reference_wrapper. But you should really fix myswap, because it's pretty useless the way it's written now.
Your myswap takes the elements by value.
Essentially you swap the two references (std::reference_wrapper s) at the local scope of the function.
The values they point to won't change.
template <typename T> void incrementer(T a) { ++a; } int a = 20;
In this case there's a conversion to int& with:
operator T& () const noexcept { return *_ptr; }
In your code, on the other hand:
T temp = a;
will simply call the copy constructor, which copies the underlying pointer:
reference_wrapper(const reference_wrapper&) noexcept = default;
then, on the next lines you again copy the pointer:
reference_wrapper& operator=(const reference_wrapper& x) noexcept = default;
I realize that there are examples after examples of overloading the assignment operator on the web, but I have spent the last few hours trying to implement them in my program and figure out how they work and I just can't seem to do it and any help would be greatly appreciated.
I am trying to implement an overloaded assignment operator function.
I have 3 files working, the Complex.h header file, a Complex.cpp definition file, and a .cpp file I'm using as a driver to test my Complex class.
In the Complex.h header file my prototype for the assignment operator:
Complex &operator= (Complex&);
And so far what I have for the definition of the overloaded operator in my .cpp file is:
Complex &Complex::operator=(Complex& first)
{
if (real == first.real && imaginary == first.imaginary)
return Complex(real, imaginary);
return first;
};
And the way I'm calling my assignment operator in my functions is:
x = y - z;
So specifically, my problem is that when I call the overloaded assignment operator with x = y -z, it doesn't assign the passed in value to x when I return the passed in value and I'm unable to figure out why from numerous examples and explanations on the web, any help would be greatly appreciated and I thank you for any help ahead of time.
I think you need the following operator definition
Complex & Complex::operator =( const Complex &first )
{
real = first.real;
imaginary = first.imaginary;
return *this;
};
You have to return reference to the object that is assigned to. Also the parameter should be a constant reference. In this case you may bind the reference to a temporary object or you have to write also a move assignment operator.
In your implementation of the copy assignment operator you do not change the assigned object.:) You simply create a temporary and return reference to this temporary or return reference to first.
Assignment takes in two objects, the object to be assigned to, and the object with the desired value.
Assignment should:
modify an existing object, the object being assigned to
Assignment should not:
create a new object
modify the object that has the desired value.
So let's say the object type we're dealing with is:
struct S {
int i;
float f;
};
A function that performs assignment might have the signature:
void assignment(S &left_hand_side, S const &right_hand_side);
And it would be used:
S a = {10, 32.0f};
S b;
assignment(b, a);
Notice:
the left hand side object is modifiable, and assignment will modify it, rather than create a new object.
the right hand side object, the object with the desired value, is not modifiable.
Additionally, in C++ the built-in assignment operation is an expression rather than a statement; it has a value and can be used as a subexpression:
int j, k = 10;
printf("%d", (j = k));
This sets j equal to k, and then takes the result of that assignment and prints it out. The important thing to note is that the result of the assignment expression is the object that was assigned to. No new object is created. In the above code, the value of j is printed (which is 10, because j was just assigned the value 10 from k).
Updating our earlier assignment function to follow this convention results in a signature like:
S &assignment(S &left_hand_side, S const &right_hand_side);
An implementation looks like:
S &assignment(S &left_hand_side, S const &right_hand_side) {
// for each member of S, assign the value of that member in
// right_hand_side to that member in left_hand_side.
left_hand_side.i = right_hand_side.i;
left_hand_side.f = right_hand_side.f;
// assignment returns the object that has been modified
return left_hand_side;
}
Note that this assignment function is not recursive; it does not use itself in the assignment, but it does use assignment of the member types.
The final piece of the puzzle is getting the syntax a = b to work, instead of assignment(a, b). In order to do this, all you have to do is make assignment () a member function:
struct S {
int i;
float f;
S &assignment(S &left_hand_side, S const &right_hand_side) {
left_hand_side.i = right_hand_side.i;
left_hand_side.f = right_hand_side.f;
return left_hand_side
}
};
Replace the left_hand_side argument with *this:
struct S {
int i;
float f;
S &assignment(S const &right_hand_side) {
this->i = right_hand_side.i;
this->f = right_hand_side.f;
return *this;
}
};
And rename the function to operator=:
struct S {
int i;
float f;
S &operator=(S const &right_hand_side) {
this->i = right_hand_side.i;
this->f = right_hand_side.f;
return *this;
}
};
int main() {
S a, b = {10, 32.f};
S &tmp = (a = b);
assert(a.i == 10);
assert(a.f == 32.f);
assert(&tmp == &a);
}
Another important thing to know is that the = sign is used in one place that is not assignment:
S a;
S b = a; // this is not assignment.
This is 'copy initialization'. It does not use operator=. It is not assignment. Try not to confuse the two.
Points to remember:
assignment modifies the object being assigned to
assignment does not modify the object being assigned from.
assignment does not create a new object.
assignment is not recursive, except insofar as assignment of a compound object makes use of assignment on all the little member objects it contains.
assignment returns the object after modifying its value
copy initialization looks sort of like assignment, but has little to do with assignment.
An overloaded assignment operator should look like this:
Complex &Complex::operator=(const Complex& rhs)
{
real = rhs.real;
imaginary = rhs.imaginary;
return *this;
};
You should also note, that if you overload the assignment operator you should overload the copy constructor for Complex in the same manner:
Complex::Complex(const Complex& rhs)
{
real = rhs.real;
imaginary = rhs.imaginary;
};
this might be a noobie question but this confuses me, especially when it comes to this pointer.
How do I know which object "this" pointer is pointing to? I can provide an example where that confuses me... Say you had this code
#include<iostream>
using namespace std;
class someClass{
int var;
//2 constructors here, one with no arguments, one with giving a value to var(not important)
someClass operator+(someClass object){
someClass rObject;
rObject.var = this->var + object.var //and here is my problem
}
};
int main() {
someClass a(20);
someClass b(30);
someClass c;
c=a+b; //????????
//rest of the code not important
}
In this case the "current object" would be the object a, but how does that make sense if we just switch sides so it's c=b+a the current object would become b... I am confused... What determines the current object?
You have chosen the more involved example: operators. In general it is easier to reason about other member functions. Consider:
struct T {
int value;
void foo() { std::cout << this->value << '\n'; }
};
int main() {
T t;
t.foo();
}
How do you know which is the current object inside foo()? It is the object on the left of the dot operator in the expression, in this case t. (Well, in this case there is no other object at all in the program!)
Now going back to operators, for binary operators in particular, many of them can be implemented in two forms, as a free function taking two arguments or as a member function taking a single argument. There is a direct transformation that the compiler will do for you in both cases:
struct T {
int value;
T operator+(T const & rhs) { T tmp; tmp.value = this->value + rhs.value; return tmp; }
};
T operator-(T const & lhs, T const & rhs) {
T tmp; tmp.value = lhs.value - rhs.value; return tmp;
}
int main() {
T a, b; a.value = 1; b.value = 2;
a - b;
a + b;
}
Then the compiler encounters the expression a - b it searches for the two possible forms of the operator, it finds that it is a free function and it binds lhs to a and rhs to b, transforming the expression into operator-(a, b). In the case of a + b, the compiler again searches for the operator and finds it as a member function, at this point the transformation becomes a.operator+(b) and the this pointer inside the member function refers once again to the object to the left of the dot operator.
Non-static class methods have an implicit first argument this of the class type. So when you write:
operator+(someClass object)
You are actually getting this:
operator+(someClass* this, someClass object)
And now you can see: the left-hand side of a binary operator is the first argument, and the right-hand side is the second argument (by convention, and because it makes more sense than the other way around).
When you execute a+b, that invokes operator +(someClass) on object a. Therefore, this is a.
It helps to first consider an easier operator, namely operator +=. It may appear to be a more advanced operator, but that's because we learned arithmetic using +. If you look at your code, you see that you typically need three objects for + c=a+b whereas += just needs two: b += a.
Now in b += a the this pointer should point to the object you're changing, i.e. b. That's the first object. To keep things simple, for all binary operators this points to the first object.
In a project of mine, I'm writing a wrapper for std::vector. I'm doing this because I am using homogeneous coordinates and for some operations it's just easier to temporarily 'forget' the fourth coordinate.
Now I stumbled upon a problem. I have loads of assignments like the following:
Vector v;
v(0) = 5;
v(1) = 6;
and so on. I also want to do the following:
double x;
x = v(0);
For that last thing, I can overload the () operator, but how would implement the first thing? (the zero and one being an index).
Just return reference.
class Vector
{
int data[4];
int & operator() (int index) { return data[index]; }
};
Return a non-const reference to the element to be modified.
Two things-
You should probably be overloading operator[] to do this rather than operator(), since it's the more natural operator here. operator() is used to create function objects, while operator[] is the operator meaning "pick out the element at this position."
You can support assignment to the result of operator[] / operator() by having the function return a reference to the value that should be written to. As a simple example, here's some code that represents a class wrapping a raw array:
(code here:)
class Array {
public:
int& operator[] (unsigned index);
int operator[] (unsigned index) const;
private:
int array[137];
};
int& Array::operator[] (unsigned index) {
return array[index];
}
int Array::operator[] (unsigned index) const {
return array[index];
}
The second of these functions is a const overload so you can have const Array read but not write values.
In the standard libraries, such things are implemented by having operator() (well, actually usually operator[]) return type double &. By returning a reference to a double, you can assign to or from it.
However, are you sure you want to wrap this around std::vector? This class is not a vector in the mathematical sense; it's much like a Java ArrayList, and so not at all efficient for small structures. Usually when I'm writing my own vector classes I'm planning on having lots of them around, so I implement a class from scratch on top of a static array.
Consider this code:
struct foo
{
int a;
};
foo q() { foo f; f.a =4; return f;}
int main()
{
foo i;
i.a = 5;
q() = i;
}
No compiler complains about it, even Clang. Why q() = ... line is correct?
No, the return value of a function is an l-value if and only if it is a reference (C++03). (5.2.2 [expr.call] / 10)
If the type returned were a basic type then this would be a compile error. (5.17 [expr.ass] / 1)
The reason that this works is that you are allowed to call member functions (even non-const member functions) on r-values of class type and the assignment of foo is an implementation defined member function: foo& foo::operator=(const foo&). The restrictions for operators in clause 5 only apply to built-in operators, (5 [expr] / 3), if overload resolution selects an overloaded function call for an operator then the restrictions for that function call apply instead.
This is why it is sometimes recommended to return objects of class type as const objects (e.g. const foo q();), however this can have a negative impact in C++0x where it can inhibit move semantics from working as they should.
Because structs can be assigned to, and your q() returns a copy of struct foo so its assigning the returned struct to the value provided.
This doesn't really do anything in this case thought because the struct falls out of scope afterwards and you don't keep a reference to it in the first place so you couldn't do anything with it anyway (in this specific code).
This makes more sense (though still not really a "best practice")
struct foo
{
int a;
};
foo* q() { foo *f = new malloc(sizeof(foo)); f->a = 4; return f; }
int main()
{
foo i;
i.a = 5;
//sets the contents of the newly created foo
//to the contents of your i variable
(*(q())) = i;
}
One interesting application of this:
void f(const std::string& x);
std::string g() { return "<tag>"; }
...
f(g() += "</tag>");
Here, g() += modifies the temporary, which may be faster that creating an additional temporary with + because the heap allocated for g()'s return value may already have enough spare capacity to accommodate </tag>.
See it run at ideone.com with GCC / C++11.
Now, which computing novice said something about optimisations and evil...? ;-].
On top of other good answers, I'd like to point out that std::tie works on top of this mechanism for unpacking data from another function. See here. So it's not error-prone per se, just keep in mind that it could be a useful design pattern