我正在使用C++编写一个小型数值分析库.我一直在尝试使用最新的C++ 11功能实现,包括移动语义.我理解以下帖子中的讨论和最佳答案:C++ 11 rvalues和移动语义混淆(return语句),但有一种情况我仍然试图包围我的头脑.
我有一个类,称之为T,它配备了重载运算符.我也有复制和移动构造函数.
T (const T &) { /*initialization via copy*/; }
T (T &&) { /*initialization via move*/; }
Run Code Online (Sandbox Code Playgroud)
我的客户端代码大量使用运算符,所以我试图确保复杂的算术表达式从移动语义中获得最大的好处.考虑以下:
T a, b, c, d, e;
T f = a + b * c - d / e;
Run Code Online (Sandbox Code Playgroud)
没有移动语义,我的操作符每次都使用复制构造函数创建一个新的局部变量,所以总共有4个副本.我希望通过移动语义,我可以将其减少到2个副本加上一些动作.在括号中:
T f = a + (b * c) - (d / e);
Run Code Online (Sandbox Code Playgroud)
每个(b * c)并且(d / e)必须以通常的方式创建临时副本,但是如果我可以利用其中一个临时工具仅用移动来累积剩余的结果,那将是很好的.
使用g ++编译器,我已经能够做到这一点,但我怀疑我的技术可能不安全,我想完全理解为什么.
以下是加法运算符的示例实现:
T operator+ (T const& x) const
{
T result(*this);
// …Run Code Online (Sandbox Code Playgroud) 意识到当一些东西看起来好得令人难以置信时,通常情况下,我想我会提出这个问题,希望能够清除掉任何一个小鬼.我回顾了一些我能找到的相关主题,但我的问题仍然存在.
我对Haskell相对较新,在我的实验中,我编写了一个基本的Fisher-Yates shuffle,如下所示.
shuffle :: RandomGen g => [a] -> g -> ([a],g)
shuffle [] g0 = ([],g0)
shuffle [x] g0 = ([x],g0)
shuffle xs g0 = (x:newtail,g2)
where (i,g1) = randomR (0, length $ tail xs) g0
(xs1,x:xs2) = splitAt i xs
(newtail,g2) = shuffle (xs1++xs2) g1
Run Code Online (Sandbox Code Playgroud)
这个实现当然使用beaucoup内存用于大型列表,但它很快 - 在我的笔记本电脑上平均为5M,30M整数与标准C++混洗2.3s).事实上,它比其他地方的其他Haskell实现要快得多.(例如,http://www.haskell.org/haskellwiki/Random_shuffle)
鉴于我看到的其他Haskell shuffle既复杂又慢,我想知道加速/简单是否仅仅是我作为一个无懈可击的记忆猪的奖励,或者我是否错过了一些微小但关键的细节,使我的算法偏向.我没有进行过广泛的测试,但是初步看起来似乎显示了排列的均匀分布.
我希望通过更多Haskell和/或改组经验评估更多的眼睛.非常感谢所有花时间回复的人.