1

我想知道,假设我有一些大对象,比如一个矩阵,并且我想提供一些功能来以某种方式修改这个对象(在矩阵的情况下,我们可能希望反转矩阵)。

实现反转功能的最佳方法是什么?

想到四个选项:

  1. 我们可以有一个成员函数 Matrix::invert() 来反转自身。
  2. 成员函数可以构造一个新的倒置矩阵(类似于std::string::substr
  3. invert 可以是一个接受和修改引用的非成员函数:void invert(matrix& m)
  4. invert 可以是一个非成员函数,它按值获取一个矩阵,反转它,然后返回它: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(),如果它在右值上被调用,它会修改父矩阵,但如果它在左值上被调用,它会保持原样并返回一个新矩阵。这会是正确的方法吗?以及如何实施?

另一种选择可能是实现一个修改原始成员的成员,以及一个“做正确的事情”的非成员,具体取决于参数是右值(在这种情况下它将被移动)还是左值(在这种情况下将制作一份副本)。这仍然有两个缺点:

  1. 更多代码,因为现在我们有两个反转函数
  2. 链接很尴尬,因为我们可能想说 m.invert() 但不想修改原始矩阵。

示例:https ://gist.github.com/mfaizan/6631482

谢谢!

4

3 回答 3

1

您可能还需要考虑另一种可能性:

bool invert (Matrix &);

矩阵可能被确定为奇异矩阵,在这种情况下返回false并保持矩阵不变。你需要某种方式来报告这种情况。

无论您使用 Cramer 规则等,对于小矩阵、缩放(部分)旋转,还是对于大矩阵更有效的方法,总是存在精度限制。也就是说,结果将受到矩阵条件的影响。关键是 - 即使矩阵在数学上是可逆的 - 浮点运算也可能不会产生逆。

“表达式”最通用的形式可能是:Matrix invert (const Matrix &);- 如果您有移动构造函数/赋值运算符。也许有一个Matrix::Singular例外类。

于 2013-09-20T02:23:17.630 回答
1

很容易想象需要破坏性和非破坏性版本的功能。例如,链表的破坏性反向可能更有效,因为它不需要复制容器值。而且毫不奇怪,STL 有reverse(破坏性)和reverse_copy(非破坏性),list还具有reverse(破坏性)成员函数。

也很容易想象可以基于某些受限接口实现的功能,但通过了解类内部知识可以大大提高其效率。例如矩阵是否稀疏。我认为在这种情况下,拥有一个将参数类型分派给辅助函数的通用接口是正常的。

于 2013-09-20T01:34:15.683 回答
1

当然,这一切都取决于,但同时具有变异动作和产生新对象的动作通常很有用。前任。您的 m.invert() 方法可以就地修改矩阵。它可能比创建新矩阵更有效(它可以更改现有值而无需分配内存)。然而,有一种方法可以创建与原点断开连接的新对象。

您在 std::string 上看到了这种模式:

string orig("abcd");
orig += "efgh";

这会使原始字符串发生变异,并且可能能够避免内存重新分配。但是,您也可以创建一个全新的字符串:

string newStr = orig + anotherStr;
于 2013-09-20T01:38:29.427 回答