PsyWhat
PsyWhat

Reputation: 55

C++ operator's optimization via templates

So, I have a C++ Matrix class, and there are some overloaded operators(like +, *, %, - atc...), they look like this:

Matrix operator*(const Matrix& b) const;

They are returning the TMP object of type Matrix, and then it's being copied, whinch decreaces the performance.

If I do something like

Matrix some = a*b + c*d - (i+j)*m*b; //[1]

There are something about 6 copy constructors being called.

So, I saw ppl doing some template metaprogramming, to expand the [1] to something like:

Matrix some = ((a*b)+=(c*d))-=(((i+j)*=m)*=b); //[2]

The code at [2] gonna call somewhere around 3 copy constructors.(*=, += writing the results to left operand and returns the link for it)

Can you guys pls explain me, how do I do that via templates, or what should I read to understand how to do that.

Upvotes: 0

Views: 58

Answers (2)

user1084944
user1084944

Reputation:

They keyword to search on is "expression templates".

A lot of things can be achieved simply by using rvalue references, though.

Incidentally, if you're really serious about it you'll want even more rewriting than your example suggests; e.g. multiply and addition steps often want to be combined into a single operation rather than two separate ones.

Upvotes: 1

PsyWhat
PsyWhat

Reputation: 55

So, as I saw in comments, compiller optimize it by itself, but, there are also some moments exists, that can be optimized.

Lets start.

  1. First of all, usually, we save the result of overloaded operators via operator=, and if we add a couple of fields in it {bool tmp, bool copied} we can skip the memory coping, its should be looks like this.

.

...freeing memory, if needed...
if(!(tmp && !copied)
{
    ...memcpy actions...
}else
{
    ...assigning a pointers to allocated data right to our objects pointers...
    this->arr = a.arr;
    a.copied = true;
}
...other post actions...

also we need to change a deconctructor

~SomeClass()
{
    if( !(tmp && copied) )//If its not a tmp and not copied then freeing
    {
        ...freeing a memory...
    }//otherwise just skeep
}
  1. In operators we usually calling an constructor for a result object, but, if one of our objects is tmp, why not to save data inside it, if its possible?

.

SomeClass operator+(SomeClass a)
{
    ...some code...
    if(!(tmp || a.tmp))//if there is no tmp object, doing the same, as usual.
    {
        SomeClass res;
        ...some usual code
        res.tmp = true;
        res.copied = false;
        return res;
    }else
    {
        if(tmp)
        {
            ...doing operations and storing them in this...
            return *this;
        }else //"a" is tmp
        {
            ...doing operations and storing them in "a"...
            return a;
        }
    }
}

so... by those actions we are decreasing the amounght of operations being called, we are saving a memory that would be allocated otherwise, also we are not copying memory from the operator results.

Now, code like this:

res = a * n + b * t - k;

will allocate memory only for a "a * n" and "b * t", then everything gonna be stored inside tmp objects of those operators results. And finally, we are not coping memory(values) from the tmp object to the "res", we are just simply assigning the pointers to a "tmp" memory(whinch is not gonna be freed).

Upvotes: 0

Related Questions