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

wtlkbnrh  于 2023-04-13  发布在  其他
关注(0)|答案(2)|浏览(89)

我正在尝试编写一个C++类,用于以特定的方式管理数据。更具体:模拟数学矩阵行为,如矩阵乘法和尽可能少的开销。直观上,我想使用重载运算符以获得更好的可读性,但我总是想知道返回结果矩阵的额外分配。特别是当你考虑一个非常大的矩阵时。
到目前为止,我已经设置好了所有的东西,通过提供维度坐标来分配和正确访问存储的数据。对象被堆分配为指针,以完成一些转换矩阵的花哨工作。到目前为止,添加看起来像这样:

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

return result;
}

所以在计算的时候,结果是直接写入result对象的,因为它是通过Pointer访问的。
但是当使用运算符重载时,我的困惑开始增加。我会实现这样的东西(简化,最小的问题):

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

想象一下我们生活在一个完美的世界里,泄漏问题被神奇地解决了,但仍然有一个问题,那就是我没有看到一种方法可以在内部为结果分配内存。如果我已经预先分配了对象,或者我从以前的计算中回收了一个对象,那么分配结果内存不是浪费了计算能力吗?有没有更有效的方法可以解决这个问题,或者可能是以某种我不知道的方式进行了内部优化?

mwyxok5s

mwyxok5s1#

在很大程度上,你担心的问题已经解决了。考虑这个虚拟矩阵和调用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?\n";        
    matrix a,b;
    matrix c = a + b;       
};

我省略了实际的矩阵元素和加法,所以我们可以专注于return result;。你担心的是复制。由于复制省略,output of the code是:

how many copies?

复制省略经历了一些实质性的变化(在某些情况下从非强制性变为强制性),有关详细信息,请参阅What are copy elision and return value optimization?https://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+返回任意自定义类型,不需要容易地计算矩阵)。

krugob8w

krugob8w2#

你可以使用shared_ptr来代替原始指针,最大的好处是它实现了你正在寻找的魔法,以避免泄漏。
也就是说,你最好管理一个Matrix对象,它将内存管理推迟到它的内部。最大的好处是你可以处理不同类型的矩阵(例如稀疏矩阵,正常矩阵等)。另一个好处是你让编译器使用移动语义和其他东西来管理优化,这不像指针那样简单。

相关问题