Yakov Dan
Yakov Dan

Reputation: 3357

Overload operator* without allocating new memory

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++.

Upvotes: 1

Views: 115

Answers (2)

eerorika
eerorika

Reputation: 238351

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.

Upvotes: 2

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 122457

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 *=.

Upvotes: 3

Related Questions