关于返回对象的运算符重载的效率

huangapple go评论59阅读模式
英文:

Efficiency of Operator overloading regarding returned Object

问题

I'm trying to write a C++ Class for managing data in a specific way. More Specific: to mimic mathmatical Matrix behavior like matrix-multiplication and stuff like that with as little overhead as possible. Intuitively i would like to use overloaded operators for better readability, but i always wonder about the additional allocation for returning the result-Matrix. Especially regarding performance if you think about a really large Matrix.

So far, i got everything set up to allocate and correctly access the stored Data by providing dimension coordinates. The objects are Heap allocated as Pointers to do some fancy stuff with transforming the Matrix. Adding looks like this so far:

Matrix* Add(Matrix* A, Matrix* B, Matrix* result)
{
[...]  //Math here

return result;
}

So when calculating, the result is directly written into the result object since its acessed via Pointer.

But when using operator overloading, my confusion starts to grow. I would implement something like this (simplified, minimal problem):

Matrix* operator+(Matrix& other)
{
Matrix* result = new Matrix;
[...] //Math here
return result;
}

Imagine we live in a perfect world and leackage is magically solved, there is still the problem, that i dont see a way around allocating memory for the result internally. If i already have the object preallocated or i recycle one from previous calculations, isn't allocating the result memory waste of computational power? Is there a more efficient way around this or is maybe somehow internally optimized in a way i dont know of?

英文:

I'm trying to write a C++ Class for managing data in a specific way. More Specific: to mimic mathmatical Matrix behavior like matrix-multiplication and stuff like that with as little overhead as possible. Intuitively i would like to use overloaded operators for better readability, but i always wonder about the additional allocation for returning the result-Matrix. Especially regarding performance if you think about a really large Matrix.

So far, i got everything set up to allocate and correctly access the stored Data by providing dimension coordinates. The objects are Heap allocated as Pointers to do some fancy stuff with transforming the Matrix. Adding looks like this so far:

Matrix* Add(Matrix* A, Matrix* B, Matrix* result)
{
[...]  //Math here

return result;
}

So when calculating, the result is directly written into the result object since its acessed via Pointer.

But when using operator overloading, my confusion starts to grow. I would implement something like this (simplified, minimal problem):

Matrix* operator+(Matrix& other)
{
Matrix* result = new Matrix;
[...] //Math here
return result;
}

Imagine we live in a perfect world and leackage is magically solved, there is still the problem, that i dont see a way around allocating memory for the result internally. If i already have the object preallocated or i recycle one from previous calculations, isn't allocating the result memory waste of computational power? Is there a more efficient way around this or is maybe somehow internally optimized in a way i dont know of?

答案1

得分: 1

大致来说,你担心的问题已经得到了解决。考虑这个虚拟矩阵和调用 operator+ 的示例:

#include <iostream>

struct matrix {
    matrix() = default;
    matrix(const matrix&) { std::cout << "copy!!!\n";}
    matrix operator+(matrix& other) {
        matrix result;
        return result;
    }
};

int main() {
    std::cout << "how many copies?";        
    matrix a, b;
    matrix c = a + b;       
};

我省略了实际的矩阵元素和加法,所以我们可以专注于 return result;。你担心的复制操作由于复制省略,代码的输出 是:

how many copies?

没有发生复制。复制省略经历了一些重大变化(从非强制性到在某些情况下强制性),有关详细信息,我建议你参考 https://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimizationhttps://en.cppreference.com/w/cpp/language/copy_elision

然而,为了在处理更复杂的表达式时获得良好的效率,例如 matrix a = (a + b) * c + (d + e) * f;,你应该考虑表达式模板(例如 https://en.wikipedia.org/wiki/Expression_templates)。这是一种推迟实际计算直到结果实际需要的技术(例如在这个示例中,从数学上讲,a+b 的结果不需要临时值,但是在C++中,尽管C++允许从 operator+ 返回任意自定义类型,但不需要立即计算矩阵)。

英文:

To large extend, the problem you are worried about has been solved already. Consider this dummy matrix and example of calling operator+:

#include &lt;iostream&gt;

struct matrix {
    matrix() = default;
    matrix(const matrix&amp;) { std::cout &lt;&lt; &quot;copy!!!\n&quot;;}
    matrix operator+(matrix&amp; other) {
        matrix result;
        return result;
    }
};


int main() {
    std::cout &lt;&lt; &quot;how many copies?\n&quot;;        
    matrix a,b;
    matrix c = a + b;       
};

I left out the actual matrix elements and the addition, so we can focus on return result;. You are worried about the copy that is made. Due to copy elision the output of the code is:

how many copies?

No copy is made. Copy elision underwent some substantial changes (from non-mandatory to mandatory in some cases), and for details i refer you to https://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization and https://en.cppreference.com/w/cpp/language/copy_elision.

However, to get good efficiency also with more complex expressions, eg matrix a = (a + b) * c + (d + e) * f;, you should consider expression templates (eg https://en.wikipedia.org/wiki/Expression_templates). Its a technique to defer actual computation until the result is actually needed (eg in the example no temporary as result of a+b is required mathematically, but by C++, though C++ allows to return arbitrary custom type from operator+, it needs not be readily computed matrix).

答案2

得分: 0

你可以使用shared_ptr代替裸指针。它的主要优势是它实现了你正在寻找的魔法功能,用于避免内存泄漏。

这就是说,最好管理一个Matrix对象,将内存管理委托给其内部。其中一个重要优势是你可以处理不同类型的矩阵(例如稀疏矩阵、普通矩阵等)。另一个好处是你可以让编译器使用移动语义等方式来进行优化,这不像使用指针那样直截了当。

英文:

You could use shared_ptr instead of raw pointers. The big advantage is that it implements the magic thing you are looking for, for avoiding leakages.

This being said, youd'd better manage a Matrix object that defers
the memory management to its internals. The big advantage is that you could deal with different kinds of matrices (e.g sparse matrix, normal matrix, etc). Another advantage is that you leave the compiler to manage the optimization using move semantics and other stuff, which is not as straightforward with pointers.

huangapple
  • 本文由 发表于 2023年4月11日 04:38:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/75980539.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定