我想知道,假设我有一些大对象,比如一个矩阵,我想提供一些功能来以某种方式修改这个对象(在矩阵的情况下,我们可能希望反转矩阵)。
实现反转功能的最佳方法是什么?
我想到了四种选择:
std::string::substr
)void invert(matrix& m)
matrix invert(matrix m)
现在,第四个选项对我来说似乎是最好的,因为如果用户希望保留原始矩阵,原件将不会被修改:
auto m = matrix{};
auto m2 = invert(m);
如果他们只想要倒置矩阵,他们可以这样做:
auto m = matrix{};
auto m2 = invert(move(m));
或
auto m = invert(matrix{})
(这应该是有效的,因为新构造的矩阵将被移动到反转,修改,然后rvo'd或移出到m)
但这违背了影响类表示的操作应该作为成员函数实现的想法。理想情况下,我想要一种实现成员函数matrix& matrix::invert()
的方法,如果在rvalue上调用它,则会修改父矩阵,但是如果在左值上调用它则保持原样并返回一个新矩阵。这是正确的做法吗?它怎么可能实现?
另一种选择可能是实现修改原始成员的成员,以及根据参数是否为rvalue(在这种情况下它将被移动)或者是左值来实现“做正确的事”的非成员(在这种情况下,将制作一份副本)。这仍然有两个缺点:
示例:https://gist.github.com/mfaizan/6631482
谢谢!
答案 0 :(得分:1)
很容易想象出需要破坏性和非破坏性版本的功能。例如,链表的破坏性反向可以更有效,因为它不需要复制容器值。毫不奇怪,STL有reverse
(破坏性)和reverse_copy
(非破坏性),但list
也有reverse
(破坏性)成员函数。
很容易想象可以基于某些受限制的界面实现的功能,但是通过类内部知识可以大大提高其效率。例如,矩阵是否稀疏。我认为在这种情况下,有一个通用接口将参数类型分派给辅助函数是正常的。
答案 1 :(得分:1)
这一切当然都取决于它,但是同时拥有导致新对象的变异动作和动作通常很有用。防爆。你的m.invert()方法可以修改矩阵。它可能比创建新矩阵更有效(它可以在不必分配内存的情况下更改现有值)。但是,有一种方法可以创建与orig断开连接的新对象。
你在std :: string上看到这种模式:
string orig("abcd");
orig += "efgh";
这会改变orig字符串,并且可能会避免内存realloc。 但是,您也可以创建一个全新的字符串:
string newStr = orig + anotherStr;
答案 2 :(得分:1)
您可能还需要考虑另一种可能性:
bool invert (Matrix &);
可以确定矩阵是单数的,在这种情况下返回false
并保持矩阵不变。您需要某种方式来报告此案例。
对于小矩阵,缩放(部分)旋转或大型矩阵的更有效方法,无论是使用Cramer规则等,总是存在精度限制。也就是说,结果将受到基质调节的影响。关键是 - 即使矩阵在数学上是可逆的 - 浮点运算也不会产生逆。
“表达式”的多功能表单可能是:Matrix invert (const Matrix &);
- 前提是你有移动构造函数/赋值运算符。也许有一个Matrix::Singular
异常类。