1

Suppose I have an object that I want to add/multiply/subtract, etc. In this case, I want to have an element-wise multiply (basically, I just run through and multiply the 1D array by another, but I would like to interact with it later on as if it is a 2D array).

This tends to be a situation where I would like to write something like:

D * (A * B * C * ...) * ...

Below, I have an example that is compatible with it:

struct Matrix{
    double * matrix_arr
    long size;
    long rows;
    long cols;

    ...   

    Matrix elementwise_product(Matrix B){ 
        ... 
        return new_matrix_C;
    } 
}

Whereupon I overload the multiply operator, and everything is ok.

The only problem is that I understand the copy constructor is called with respect to objects returned by value, and I am creating objects which may be large.

I could do everything by allocating memory in higher scope, and performing the calculations with a pre-allocated result array, but then I lose the D*(A*B*C*...) syntax which is very desireable.

How do I both get the syntax, and avoid the copy constructor?

Chris
  • 28,822
  • 27
  • 83
  • 158
  • 4
    https://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization – Oliver Charlesworth Dec 24 '17 at 20:16
  • 8
    Set aside about 3-6 months of your time, and learn how to use C++11's move constructors and move assignment operators. This is exactly what they're for. – Sam Varshavchik Dec 24 '17 at 20:16
  • 7
    I am not making a joke here. If you don't know what move semantics are, you'll need quite a bit of time learning what it is, and how it works. This is one of the most advanced features of modern C++, but it is designed precisely for the situation here: you have objects that are expensive to copy around, but are perfectly aligned for supporting move semantics. – Sam Varshavchik Dec 24 '17 at 20:18
  • @SamVarshavchik lol I took you seriously as well. Thank you for the search terms! – Chris Dec 24 '17 at 20:19
  • I think the above comments are super useful, but I'll delete the question if it seems too redundant. – Chris Dec 24 '17 at 20:20
  • 2
    If, as you're studying this topic, you reach the conclusion that you need to implement multiplication, addition, etc... operators that take rvalue references as a parameter, you know that you're on the right track. Use it as a goalpost. – Sam Varshavchik Dec 24 '17 at 20:20
  • 4
    If you feel comfortable writing a class and overriding operators, then move semantics should only take <1 day to learn, not months. – Mooing Duck Dec 24 '17 at 20:24
  • @MooingDuck thanks man--that's encouraging. working through a good reference now... – Chris Dec 24 '17 at 21:10
  • 3
    Actually, the comments about move construction sound nice but are likely besides the point. The cost of repeatedly accessing data which isn’t hot in the cache is likely the dominant aspect and isn’t solved by move construction. What is needed instead is to aggregate operations horizontally, i.e., to chain all operations on a position across the entire expression. The tool of choice are [Expression Templates](https://en.m.wikipedia.org/wiki/Expression_templates). – Dietmar Kühl Dec 24 '17 at 21:31
  • To add one more step to move and expr tmplt, you really should use associativity where available. This makes multiplication orders of magnitude faster if matrices are far from rectangular (and/or are sparse). – lorro Dec 24 '17 at 21:38
  • @DietmarKühl @Iorro ah, I see what is going on. And, from the docs, I see how it may be beside the point as well. With respect to the associativity, I think it looks like i'll probably drop the friendly syntax (for a vector) for the higher speed, but keep it around in the library--don't see a way to preserve the `A * B * C` syntax, and then calculate the best ordering. – Chris Dec 24 '17 at 21:57
  • Actually, the syntax stays the same! That’s the entire point. However, instead of returning the result the operators return an expression tree which gets evaluated upon turning the result into the correct type. Since there is more context available when the entire expeession is visible it can be executed more effectively. – Dietmar Kühl Dec 24 '17 at 22:01
  • I second the above. This is a situation where you want move semantics – Qwertycrackers Dec 24 '17 at 22:07

0 Answers0