Big Ben

一个半吊子的编码爱好者

0%

Edit

Batch. vs. Mini-Batch

机器学习算法通常会有大量的training sample需要处理,这个数字可能是百万量级,甚至更高。这会导致矩阵迭代的时候,计算时间过长。当sample数达到一定数量的时候,通常会采用将整个训练集,分成若干小集合,即mini-batch,采用迭代的方法来计算。这样就将一次矩阵运算串行化,降低运算复杂度,速度会大幅提升。缺点是收敛会困难一些。看下图:

How to choose mini-batch size?

  • If small training set (m 2000), use batch gradient descent.
  • Typical mini-batch size: 64, 128, 256, 512, -> ~
  • Make sure mini-batch size fit your CPU/GPU memory.

Learning Rate Decay

动态调整learning rate的算法有很多种,下面这种是比较常用的

epoch_num = 1,2,3,
随着epoch_num越来越大,越来越小。

Other learning rate decay methods:

  • discrete stair case
  • manual decay

指数加权平均相关算法

Momentum, RMSprop, Adam都是和指数加权平均算法(Exponential Weighted Average)相关的。下面一一介绍:

Exponential Weighted Average

公式是:

其用意就是对过去个数据进行平均,并添加权重,对本轮数据采用权重。例如,则会加权平均前10个数据,并添加0.1本轮数据。其效果如下图:

  • 蓝点是原始数据
  • 红线采用,累积前10个数据的影响
  • 绿线采用,累积前20个数据的影响
  • 黄线采用,累积前2个数据的影响
    可见,采用指数加权平均后,数据变平滑,且越大,数据越平滑,越小,数据越趋近于原始数据。

How it works?

其工作原理如下图:

Bias Correction Exponential Weighted Average

之所以有这个bias correction,因为这个指数加权的初始值选的是0,造成开始一段的迭代,会偏离真实值较远。例如下面绿线和紫线。

当开始阶段,t比较小,也比较小,这样可以让计算出来的没那么小,以达到纠正偏差的效果。

Momentum

Momentum就是指数加权平均算法的一种应用。

RMSprop (Root Mean Square prop)

RMSprop是根据Momentum衍生出来的算法。具体做法如下:

On iteration t:

  • Compute dw and db on current mini-batch

为了区分Momentum和Exponential Weighted Average中的hyper parameter ,此处用

Adam optimization algorithm

Adam = Adaptive Moment Estimation
Adam = Momentum + Bias Correction + RMSprop
具体算法如下:


On iteration t:

  • Compute dw and db on current mini-batch
  • ,
  • ,
  • ,
  • ,

Hyper parameters (通常去经验值)

Local Optima Problem

Andrew解释了,在现代的机器学习问题中,不太可能出现local optima

%23%20Deep%20Learning%20%283%29%20-%20Optimization%20Algorithms%0A@%28myblog%29%5Bdeep%20learning%2C%20machine%20learning%5D%0A%0A%23%23%20Batch.%20vs.%20Mini-Batch%0A%u673A%u5668%u5B66%u4E60%u7B97%u6CD5%u901A%u5E38%u4F1A%u6709%u5927%u91CF%u7684training%20sample%u9700%u8981%u5904%u7406%uFF0C%u8FD9%u4E2A%u6570%u5B57%u53EF%u80FD%u662F%u767E%u4E07%u91CF%u7EA7%uFF0C%u751A%u81F3%u66F4%u9AD8%u3002%u8FD9%u4F1A%u5BFC%u81F4%u77E9%u9635%u8FED%u4EE3%u7684%u65F6%u5019%uFF0C%u8BA1%u7B97%u65F6%u95F4%u8FC7%u957F%u3002%u5F53sample%u6570%u8FBE%u5230%u4E00%u5B9A%u6570%u91CF%u7684%u65F6%u5019%uFF0C%u901A%u5E38%u4F1A%u91C7%u7528%u5C06%u6574%u4E2A%u8BAD%u7EC3%u96C6%uFF0C%u5206%u6210%u82E5%u5E72%u5C0F%u96C6%u5408%uFF0C%u5373mini-batch%uFF0C%u91C7%u7528%u8FED%u4EE3%u7684%u65B9%u6CD5%u6765%u8BA1%u7B97%u3002%u8FD9%u6837%u5C31%u5C06%u4E00%u6B21%u77E9%u9635%u8FD0%u7B97%u4E32%u884C%u5316%uFF0C%u964D%u4F4E%u8FD0%u7B97%u590D%u6742%u5EA6%uFF0C%u901F%u5EA6%u4F1A%u5927%u5E45%u63D0%u5347%u3002%u7F3A%u70B9%u662F%u6536%u655B%u4F1A%u56F0%u96BE%u4E00%u4E9B%u3002%u770B%u4E0B%u56FE%uFF1A%0A%21%5BAlt%20text%7C300x0%5D%28./1534979648469.png%29%0A%u84DD%u7EBF%u662Fbatch%20gradient%20descent%uFF0C%u7D2B%u7EBF%u662Fstochastic%20gradient%20descent%20%28mini-batch%20size%20%3D%201%29%uFF0C%u7EFF%u7EBF%u662Fmini-batch%20gradient%20descent%20%281%24%5Clt%24mini-batch%20size%20%24%5Clt%24%20m%29%u3002%0A%u84DD%u7EBF%u53EF%u4EE5%u5E73%u6ED1%u7684%u6536%u655B%u5230%u6781%u503C%u70B9%uFF0C%u7D2B%u7EBF%u5728%u6781%u503C%u70B9%u9644%u8FD1%u5267%u70C8%u632F%u52A8%uFF0C%u7EFF%u7EBF%u4ECB%u4E8E%u7D2B%u7EBF%u548C%u84DD%u7EBF%u4E4B%u95F4%uFF0C%u5728%u6781%u503C%u70B9%u9644%u8FD1%u5C0F%u5E45%u7684%u5F98%u5F8A%u3002%u53EF%u4EE5%u901A%u8FC7%u52A8%u6001%u8C03%u6574learning%20rate%u6765%u8BA9%u4ED6%u8FDB%u4E00%u6B65%u6536%u655B%u5230%u6781%u503C%u70B9%u3002%0A%0A%23%23%23%20How%20to%20choose%20mini-batch%20size%3F%0A-%20If%20small%20training%20set%20%28m%20%24%5Cle%24%202000%29%2C%20use%20batch%20gradient%20descent.%0A-%20Typical%20mini-batch%20size%3A%2064%2C%20128%2C%20256%2C%20512%2C%20%24%5Cdots%24%20-%3E%20%242%5E6%24%7E%242%5E9%24%0A-%20Make%20sure%20mini-batch%20size%20fit%20your%20CPU/GPU%20memory.%0A%0A%23%23%23%20Learning%20Rate%20Decay%0A%u52A8%u6001%u8C03%u6574learning%20rate%u7684%u7B97%u6CD5%u6709%u5F88%u591A%u79CD%uFF0C%u4E0B%u9762%u8FD9%u79CD%u662F%u6BD4%u8F83%u5E38%u7528%u7684%0A%24%24%5Calpha%20%3D%20%5Cfrac%20%7B1%7D%7B1+decay%5C_rate%20*%20epoch%5C_num%7D%20%5Calpha_0%24%24%0Aepoch_num%20%3D%201%2C2%2C3%2C%24%5Cdots%24%0A%u968F%u7740epoch_num%u8D8A%u6765%u8D8A%u5927%uFF0C%24%5Calpha%24%u8D8A%u6765%u8D8A%u5C0F%u3002%0A%3E%20Other%20learning%20rate%20decay%20methods%3A%0A%3E%20-%20%24%5Calpha%20%3D%200.95%5E%7Bepoch%5C_num%7D%5Calpha0%24%0A%3E%20-%20%24%5Calpha%20%3D%20%5Cfrac%20%7Bk%7D%20%7B%5Csqrt%20%7Bepoch%5C_num%7D%7D%20%5Calpha_0%24%0A%3E%20-%20discrete%20stair%20case%0A%3E%20-%20manual%20decay%0A%0A%23%23%20%u6307%u6570%u52A0%u6743%u5E73%u5747%u76F8%u5173%u7B97%u6CD5%0AMomentum%2C%20RMSprop%2C%20Adam%u90FD%u662F%u548C%u6307%u6570%u52A0%u6743%u5E73%u5747%u7B97%u6CD5%28Exponential%20Weighted%20Average%29%u76F8%u5173%u7684%u3002%u4E0B%u9762%u4E00%u4E00%u4ECB%u7ECD%uFF1A%0A%0A%23%23%23%20Exponential%20Weighted%20Average%0A%u516C%u5F0F%u662F%3A%0A%24%24v_t%20%3D%20%5Cbeta%20v_%7Bt-1%7D%20+%20%281-%5Cbeta%29%5Ctheta_t%24%24%0A%u5176%u7528%u610F%u5C31%u662F%u5BF9%u8FC7%u53BB%24%5Cfrac%20%7B1%7D%7B1-%5Cbeta%7D%24%u4E2A%u6570%u636E%u8FDB%u884C%u5E73%u5747%uFF0C%u5E76%u6DFB%u52A0%u6743%u91CD%24%5Cbeta%24%uFF0C%u5BF9%u672C%u8F6E%u6570%u636E%u91C7%u7528%u6743%u91CD%241-%5Cbeta%24%u3002%u4F8B%u5982%24%5Cbeta%20%3D%200.9%24%uFF0C%u5219%u4F1A%u52A0%u6743%u5E73%u5747%u524D10%u4E2A%u6570%u636E%uFF0C%u5E76%u6DFB%u52A00.1%u672C%u8F6E%u6570%u636E%u3002%u5176%u6548%u679C%u5982%u4E0B%u56FE%uFF1A%0A%21%5BAlt%20text%7C450x0%5D%28./1534980671272.png%29%0A-%20%u84DD%u70B9%u662F%u539F%u59CB%u6570%u636E%0A-%20%u7EA2%u7EBF%u91C7%u7528%24%5Cbeta%20%3D%200.9%24%uFF0C%u7D2F%u79EF%u524D10%u4E2A%u6570%u636E%u7684%u5F71%u54CD%0A-%20%u7EFF%u7EBF%u91C7%u7528%24%5Cbeta%20%3D%200.98%24%uFF0C%u7D2F%u79EF%u524D20%u4E2A%u6570%u636E%u7684%u5F71%u54CD%0A-%20%u9EC4%u7EBF%u91C7%u7528%24%5Cbeta%20%3D%200.5%24%uFF0C%u7D2F%u79EF%u524D2%u4E2A%u6570%u636E%u7684%u5F71%u54CD%0A%u53EF%u89C1%uFF0C%u91C7%u7528%u6307%u6570%u52A0%u6743%u5E73%u5747%u540E%uFF0C%u6570%u636E%u53D8%u5E73%u6ED1%uFF0C%u4E14%24%5Cbeta%24%u8D8A%u5927%uFF0C%u6570%u636E%u8D8A%u5E73%u6ED1%uFF0C%24%5Cbeta%24%u8D8A%u5C0F%uFF0C%u6570%u636E%u8D8A%u8D8B%u8FD1%u4E8E%u539F%u59CB%u6570%u636E%u3002%0A%0A%23%23%23%23%20How%20it%20works%3F%0A%u5176%u5DE5%u4F5C%u539F%u7406%u5982%u4E0B%u56FE%uFF1A%0A%21%5BAlt%20text%5D%28./1534981358549.png%29%0A%u6839%u636E%u7814%u7A76%u6709%u516C%u5F0F%24%281-%5Cepsilon%29%5E%7B%5Cfrac%7B1%7D%7B%5Cepsilon%7D%7D%20%5Capprox%200.35%24%uFF0C%24%5Cepsilon%20%3D%201-%5Cbeta%24%uFF0C%241-%5Cbeta%24%u540E%u7684%u6570%u636E%u6743%u503C%u5C31%u5F88%u5C0F%u4E86%uFF0C%u4F8B%u5982%24%5Cbeta%3D0.9%24%uFF0Ct%3D10%u4EE5%u540E%u6743%u503C%u7EA6%u4E3A%24%5Cbeta%281-%5Cbeta%29%5Et%20%3D%200.1*0.9%5E%7B10%7D%20%5Capprox%200.035%24%uFF0C%u82E5%24%5Cbeta%20%3D%200.98%24%uFF0Ct%3D50%u4EE5%u540E%u6743%u503C%u4E3A%24%5Cbeta%281-%5Cbeta%29%5Et%20%3D%200.02*0.98%5E%7B50%7D%20%5Capprox%200.007%24%uFF0C%u6240%u4EE5%u901A%u5E38%u53EA%u8003%u8651%u524D%24%5Cfrac%20%7B1%7D%7B1-%5Cbeta%7D%24%u4E2A%u6570%u636E%u5E26%u6765%u7684%u5F71%u54CD%u3002%0A%0A%23%23%23%23%20Bias%20Correction%20Exponential%20Weighted%20Average%0A%u4E4B%u6240%u4EE5%u6709%u8FD9%u4E2Abias%20correction%uFF0C%u56E0%u4E3A%u8FD9%u4E2A%u6307%u6570%u52A0%u6743%u7684%u521D%u59CB%u503C%u9009%u7684%u662F0%uFF0C%u9020%u6210%u5F00%u59CB%u4E00%u6BB5%u7684%u8FED%u4EE3%uFF0C%u4F1A%u504F%u79BB%u771F%u5B9E%u503C%u8F83%u8FDC%u3002%u4F8B%u5982%u4E0B%u9762%u7EFF%u7EBF%u548C%u7D2B%u7EBF%u3002%0A%21%5BAlt%20text%5D%28./1535013368575.png%29%0A%u5177%u4F53%u7B97%u6CD5%u5982%u4E0B%uFF1A%0A%24%24v_t%20%3D%20%5Cfrac%20%7Bv_t%7D%7B1-%5Cbeta%5Et%7D%24%24%0A%u5F53%u5F00%u59CB%u9636%u6BB5%uFF0Ct%u6BD4%u8F83%u5C0F%uFF0C%24%5Cfrac%20%7B1%7D%7B1-%5Cbeta%5Et%7D%24%u4E5F%u6BD4%u8F83%u5C0F%uFF0C%u8FD9%u6837%u53EF%u4EE5%u8BA9%u8BA1%u7B97%u51FA%u6765%u7684%24v_t%24%u6CA1%u90A3%u4E48%u5C0F%uFF0C%u4EE5%u8FBE%u5230%u7EA0%u6B63%u504F%u5DEE%u7684%u6548%u679C%u3002%0A%0A%0A%23%23%23%20Momentum%0AMomentum%u5C31%u662F%u6307%u6570%u52A0%u6743%u5E73%u5747%u7B97%u6CD5%u7684%u4E00%u79CD%u5E94%u7528%u3002%0A%21%5BAlt%20text%5D%28./1535016214569.png%29%0A%u901A%u5E38%u6211%u4EEC%u60F3%u52A0%u5FEB%u6A2A%u5411%u7684%u79FB%u52A8%uFF0C%u51CF%u5C11%u7EB5%u5411%u7684%u632F%u52A8%u3002%u6240%u4EE5%u6307%u6570%u52A0%u6743%u5E73%u5747%u53EF%u4EE5%u5E2E%u5FD9%u3002%0A%21%5BAlt%20text%7C450x0%5D%28./1535013718754.png%29%0AMomentum%u901A%u5E38%u4E0D%u7528bias%20correction%u3002%u56E0%u4E3Abias%u53EA%u4F1A%u5F71%u54CD%u524D%u51E0%u8F6E%u8FED%u4EE3%uFF0C%u4E0D%u4F1A%u5F71%u54CD%u5230%u540E%u9762%u8FED%u4EE3%u7684%u6536%u655B%u3002%0A%0A%23%23%23%20RMSprop%20%28Root%20Mean%20Square%20prop%29%0ARMSprop%u662F%u6839%u636EMomentum%u884D%u751F%u51FA%u6765%u7684%u7B97%u6CD5%u3002%u5177%u4F53%u505A%u6CD5%u5982%u4E0B%uFF1A%0A%3E%20On%20iteration%20t%3A%0A-%20Compute%20dw%20and%20db%20on%20current%20mini-batch%0A-%20%24S_%7Bdw%7D%20%3D%20%5Cbeta_2%20S_%7Bdw%7D%20+%20%281-%5Cbeta_2%29dw%5E2%24%0A-%20%24S_%7Bdb%7D%20%3D%20%5Cbeta_2%20S_%7Bdb%7D%20+%20%281-%5Cbeta_2%29db%5E2%24%0A-%20%24w%20%3A%3D%20w-%5Calpha%20%5Cfrac%7Bdw%7D%7B%5Csqrt%20%7BS_%7Bdw%7D%7D%20+%20%5Cepsilon%7D%24%0A-%20%24b%20%3A%3D%20b-%5Calpha%20%5Cfrac%7Bdb%7D%7B%5Csqrt%20%7BS_%7Bdb%7D%7D%20+%20%5Cepsilon%7D%24%0A-%20%24%5Cepsilon%20%3D%2010%5E%7B-8%7D%24%0A%0A%u4E3A%u4E86%u533A%u5206Momentum%u548CExponential%20Weighted%20Average%u4E2D%u7684hyper%20parameter%20%24%5Cbeta%24%uFF0C%u6B64%u5904%u7528%24%5Cbeta_2%24%0A%0A%23%23%23%20Adam%20optimization%20algorithm%0AAdam%20%3D%20Adaptive%20Moment%20Estimation%0AAdam%20%3D%20Momentum%20+%20Bias%20Correction%20+%20RMSprop%0A%u5177%u4F53%u7B97%u6CD5%u5982%u4E0B%uFF1A%0A%3E%20%24v_%7Bdw%7D%20%3D%200%2C%20S_%7Bdw%7D%20%3D%200%2C%20v_%7Bdb%7D%20%3D%200%2C%20S_%7Bdb%7D%20%3D%200%24%0AOn%20iteration%20t%3A%0A-%20Compute%20dw%20and%20db%20on%20current%20mini-batch%0A-%20%24v_%7Bdw%7D%20%3D%20%5Cbeta_1%20v_%7Bdw%7D%20+%20%281-%5Cbeta_1%29dw%24%2C%20%24S_%7Bdw%7D%20%3D%20%5Cbeta_2%20S_%7Bdw%7D%20+%20%281-%5Cbeta_2%29dw%5E2%24%0A-%20%24v_%7Bdb%7D%20%3D%20%5Cbeta_1%20v_%7Bdb%7D%20+%20%281-%5Cbeta_1%29db%24%2C%20%24S_%7Bdb%7D%20%3D%20%5Cbeta_2%20S_%7Bdb%7D%20+%20%281-%5Cbeta_2%29db%5E2%24%0A-%20%24v_%7Bdw%7D%5E%7Bcorrected%7D%20%3D%20%5Cfrac%20%7Bv_%7Bdw%7D%7D%7B1-%5Cbeta_1%5Et%7D%24%2C%20%24v_%7Bdb%7D%5E%7Bcorrected%7D%20%3D%20%5Cfrac%20%7Bv_%7Bdb%7D%7D%7B1-%5Cbeta_1%5Et%7D%24%0A-%20%24S_%7Bdw%7D%5E%7Bcorrected%7D%20%3D%20%5Cfrac%20%7BS_%7Bdw%7D%7D%7B1-%5Cbeta_2%5Et%7D%24%2C%20%24S_%7Bdb%7D%5E%7Bcorrected%7D%20%3D%20%5Cfrac%20%7BS_%7Bdb%7D%7D%7B1-%5Cbeta_2%5Et%7D%24%0A-%20%24w%20%3A%3D%20w-%5Calpha%20%5Cfrac%7Bv_%7Bdw%7D%5E%7Bcorrected%7D%7D%7B%5Csqrt%20%7BS_%7Bdw%7D%5E%7Bcorrected%7D%7D%20+%20%5Cepsilon%7D%24%0A-%20%24b%20%3A%3D%20b-%5Calpha%20%5Cfrac%7Bv_%7Bdb%7D%5E%7Bcorrected%7D%7D%7B%5Csqrt%20%7BS_%7Bdb%7D%5E%7Bcorrected%7D%7D%20+%20%5Cepsilon%7D%24%0A%0A%3E%20Hyper%20parameters%20%28%u901A%u5E38%u53BB%u7ECF%u9A8C%u503C%29%0A%3E%20%21%5BAlt%20text%7C300x0%5D%28./1535017116124.png%29%0A%0A%23%23%20Local%20Optima%20Problem%0AAndrew%u89E3%u91CA%u4E86%uFF0C%u5728%u73B0%u4EE3%u7684%u673A%u5668%u5B66%u4E60%u95EE%u9898%u4E2D%uFF0C%u4E0D%u592A%u53EF%u80FD%u51FA%u73B0local%20optima%0A%21%5BAlt%20text%5D%28./1535017928729.png%29%0A%u4F8B%u5982%u4E0A%u56FE%uFF0C%u770B%u8D77%u6765%u6709%u5F88%u591Alocal%20optima%uFF0C%u6709%u4E00%u4E2Aglobal%20optima%u3002%u4F46%u5176%u5B9E%u73B0%u5B9E%u5E76%u4E0D%u662F%u8FD9%u6837%uFF0C%u56E0%u4E3A%u8FD9%u91CC%u53EA%u662F%u4E09%u7EF4%u56FE%uFF0C%u53EA%u80FD%u753B%u51FA%u5173%u4E8E%u635F%u5931%u51FD%u6570J%u7684%u4E24%u4E2A%u7EF4%u5EA6%u3002%u4F46%u4E8B%u5B9E%u4E0AJ%u4E0Ew%u548Cb%u6709%u5173%uFF0C%u800Cw%u662F%u4E00%u4E2A%u77E9%u9635%uFF0C%u6709%u5F88%u591A%u5143%u7D20%uFF0Clocal%20optima%u8981%u6C42%u6240%u6709%u5143%u7D20%u7684%u5206%u6B65%u90FD%u8981%u6EE1%u8DB3%u6781%u503C%u70B9%u7684%u8981%u6C42%uFF0C%u5728w%u7EF4%u5EA6%u5F88%u9AD8%u65F6%uFF0C%u5E76%u4E0D%u592A%u53EF%u80FD%u51FA%u73B0%u3002%u6240%u4EE5%u4E0D%u9700%u8981%u62C5%u5FC3local%20optima%u7684%u95EE%u9898%u3002%0A%0A%0A

Edit

在机器学习中,有两种常见的问题:

  • bias (或者hIgh bias, underfitting,欠拟合)
  • variance (或者high variance, overfitting, 过拟合)

前者通常因为模型不够复杂,不足以通过现有数据预测出正确的结果。training error过大。解决的方法可以通过增大训练网络。
而后者是因为模型过于依赖训练数据,而对测试数据效果不佳。training error不大,但是dev error却比较大。改善的办法是正则化,即Regularization。

Regularization

加入正则化因素的损失函数如下:

(1)式中没有对b进行正则化,即没有。原因是b只是一个常数,而w通常是一个大矩阵,数据比较多,容易出现过拟合。添加b也可以,但通常对运算结果影响不大。

(1)式的正则项,称为L2 regularization。通常有下面几种:

  • L2 regularization (又叫weight decay):
  • L1 regularization:
  • Frobenius regularization:
  • Dropout regularization: 在另一章单独阐述。

L2 regularization = weight decay
因为当我们使用正则化的损失函数求导时有:


我的理解,因为w在减小,所以叫权重衰减。

Dropout regularization

Dropout就是随机删除一些hidden unit来实现正则化。

Implementation Example (Inverted Dropout)

这是最常见的Dropout实现方法,叫”Inverted Dropout” (反向随机Dropout)。计算步骤如下:

d3 = np.random.rand(a3.shape[0], a3.shape[1]) < keep-prob
a3 = np.multiply(a3, d3)
a3 /= keep-prob

解释一下:

  1. keep-prob代表保留hidden unit的概率。如果keep-prob = 0.8,则有80%的unit被保留,20%的unit被删除
  2. 之所以最后一行要re-scale,因为a3被删除掉一些unit,他的期望值就只有原先的keep-prob的比例,所以这里需要re-scale,这样在验证test set的时候不会有scaling的问题
  3. 注意:第一行用的是np.random.rand而不是np.random.randn。因为randn获取的随机数是正态分步,所以并不能保证小于keep-prob的概率为keep-probrand产生的是均匀分步,则能保证。

Make Prediction at Test Time

验证的时候,不使用Dropout。因为引入Dropout就是引入随机噪声,会导致预测值即不稳定。所以验证时通常不用Dropout。

Other Regularization

  • Augment data set.
    • 将原有图片进行处理得到更大的training set来消除variance。例如旋转,反转图片
  • Early Stopping
    • 在variance问题还不是很明显的时候stop,看下图,在中间的点处就停止迭代。

Vanishing/Exploding Gradients

梯度消失和梯度爆炸。这是为什么神经网络为什么不能很深。

以这样的网络举例。采用线性激活函数,即g(z)=z,则

正比于,如果w中有小于1的数,乘n次后就会接近于0,此为梯度消失,反之则为梯度爆炸。至今仍没有很好的办法可以消除这两种问题。但是可以通过随机初始化权重矩阵的方式来改进。具体做法如下:

当采用ReLU激活函数时,期望方差为,(2)式中的常数变成2即可:
当采用tanh激活函数时,公式同(2)。
(2)式中的平方项又叫Xavier Initialization,即
(3)式中的平方项叫He Initialization,即

Conclusion for random weight initialization

  • Different initializations lead to different results
  • Random initialization is used to break symmetry and make sure different hidden units can learn different things
  • Don’t intialize to values that are too large
  • He initialization works well for networks with ReLU activations.

%23%20Deep%20Learning%20%282%29%20-%20Regularization%0A@%28myblog%29%5Bdeep%20learning%5D%0A%0A%u5728%u673A%u5668%u5B66%u4E60%u4E2D%uFF0C%u6709%u4E24%u79CD%u5E38%u89C1%u7684%u95EE%u9898%uFF1A%0A-%20bias%20%28%u6216%u8005hIgh%20bias%2C%20underfitting%uFF0C%u6B20%u62DF%u5408%29%0A-%20variance%20%28%u6216%u8005high%20variance%2C%20overfitting%2C%20%u8FC7%u62DF%u5408%29%0A%0A%u524D%u8005%u901A%u5E38%u56E0%u4E3A%u6A21%u578B%u4E0D%u591F%u590D%u6742%uFF0C%u4E0D%u8DB3%u4EE5%u901A%u8FC7%u73B0%u6709%u6570%u636E%u9884%u6D4B%u51FA%u6B63%u786E%u7684%u7ED3%u679C%u3002training%20error%u8FC7%u5927%u3002%u89E3%u51B3%u7684%u65B9%u6CD5%u53EF%u4EE5%u901A%u8FC7%u589E%u5927%u8BAD%u7EC3%u7F51%u7EDC%u3002%0A%u800C%u540E%u8005%u662F%u56E0%u4E3A%u6A21%u578B%u8FC7%u4E8E%u4F9D%u8D56%u8BAD%u7EC3%u6570%u636E%uFF0C%u800C%u5BF9%u6D4B%u8BD5%u6570%u636E%u6548%u679C%u4E0D%u4F73%u3002training%20error%u4E0D%u5927%uFF0C%u4F46%u662Fdev%20error%u5374%u6BD4%u8F83%u5927%u3002%u6539%u5584%u7684%u529E%u6CD5%u662F%u6B63%u5219%u5316%uFF0C%u5373Regularization%u3002%0A%0A%23%23%20Regularization%0A%u52A0%u5165%u6B63%u5219%u5316%u56E0%u7D20%u7684%u635F%u5931%u51FD%u6570%u5982%u4E0B%uFF1A%0A%24%24J%28w%2C%20b%29%20%3D%20%20%5Cdfrac%7B1%7D%7Bm%7D%20%5CSigma_%7Bi%3D1%7D%5E%7Bm%7D%20%5Cmathscr%20L%28%5Chat%20y%5E%7B%28i%29%7D%2C%20y%5E%7B%28i%29%7D%29%20+%20%5Cfrac%7B%5Clambda%7D%7B2m%7D%20%5Cbegin%7BVmatrix%7Dx%5Cend%7BVmatrix%7D_2%5E2%20%5Ctag%201%24%24%0A%0A%3E%20%281%29%u5F0F%u4E2D%u6CA1%u6709%u5BF9b%u8FDB%u884C%u6B63%u5219%u5316%uFF0C%u5373%u6CA1%u6709%24%5Cfrac%7B%5Clambda%7D%7B2m%7Db%5E2%24%u3002%u539F%u56E0%u662Fb%u53EA%u662F%u4E00%u4E2A%u5E38%u6570%uFF0C%u800Cw%u901A%u5E38%u662F%u4E00%u4E2A%u5927%u77E9%u9635%uFF0C%u6570%u636E%u6BD4%u8F83%u591A%uFF0C%u5BB9%u6613%u51FA%u73B0%u8FC7%u62DF%u5408%u3002%u6DFB%u52A0b%u4E5F%u53EF%u4EE5%uFF0C%u4F46%u901A%u5E38%u5BF9%u8FD0%u7B97%u7ED3%u679C%u5F71%u54CD%u4E0D%u5927%u3002%0A%0A%281%29%u5F0F%u7684%u6B63%u5219%u9879%24%20%5Cfrac%7B%5Clambda%7D%7B2m%7D%20%5Cbegin%7BVmatrix%7Dx%5Cend%7BVmatrix%7D_2%5E2%24%uFF0C%u79F0%u4E3A***L2%20regularization***%u3002%u901A%u5E38%u6709%u4E0B%u9762%u51E0%u79CD%uFF1A%0A-%20L2%20regularization%20%28%u53C8%u53EBweight%20decay%29%3A%20%20%20%24%5Cfrac%7B%5Clambda%7D%7B2m%7D%20%5Cbegin%7BVmatrix%7Dx%5Cend%7BVmatrix%7D_2%5E2%20%3D%20%5CSigma_%7Bj%3D1%7D%5E%7Bn_x%7Dw%5ETw%24%20%0A-%20L1%20regularization%3A%20%24%20%5Cfrac%7B%5Clambda%7D%7B2m%7D%20%5Cbegin%7Bvmatrix%7Dx%5Cend%7Bvmatrix%7D_1%20%20%3D%20%5CSigma_%7Bj%3D1%7D%5E%7Bn_x%7D%20%5Cbegin%7Bvmatrix%7Dx%5Cend%7Bvmatrix%7D%24%0A-%20Frobenius%20regularization%3A%20%24%5Cfrac%7B%5Clambda%7D%7B2m%7D%20%5Cbegin%7BVmatrix%7Dx%5Cend%7BVmatrix%7D_F%5E2%20%3D%20%5CSigma_%7Bi%3D1%7D%5E%7Bn%5E%7B%5Bl-1%5D%7D%7D%5CSigma_%7Bj%3D1%7D%5E%7Bn%5El%7D%28w_%7Bij%7D%5E%7B%5Bl%5D%7D%29%5E2%24%20%0A-%20Dropout%20regularization%3A%20%u5728%u53E6%u4E00%u7AE0%u5355%u72EC%u9610%u8FF0%u3002%0A%0A%3E%20**L2%20regularization%20%3D%20weight%20decay**%0A%3E%20%u56E0%u4E3A%u5F53%u6211%u4EEC%u4F7F%u7528%u6B63%u5219%u5316%u7684%u635F%u5931%u51FD%u6570%u6C42%u5BFC%u65F6%u6709%uFF1A%0A%3E%20%24dw%5E%7B%5Bl%5D%7D%20%3D%20%5Cfrac%20%7B%5Cpartial%20J%7D%7B%5Cpartial%20w%7D%20%3D%20%28from%20%5Cspace%20backprop%29%20+%20%5Cfrac%20%7B%5Clambda%7D%7Bm%7Dw%5E%7B%5Bl%5D%7D%24%0A%3E%20%24w%5E%7B%5Bl%5D%7D%20%3D%20w%5E%7B%5Bl%5D%7D%20-%20%5Calpha%20%5Cspace%20dw%5E%7B%5Bl%5D%7D%20%24%0A%u6211%u7684%u7406%u89E3%uFF0C%u56E0%u4E3Aw%u5728%u51CF%u5C0F%uFF0C%u6240%u4EE5%u53EB%u6743%u91CD%u8870%u51CF%u3002%0A%0A%23%23%20Dropout%20regularization%0ADropout%u5C31%u662F%u968F%u673A%u5220%u9664%u4E00%u4E9Bhidden%20unit%u6765%u5B9E%u73B0%u6B63%u5219%u5316%u3002%0A%21%5BAlt%20text%5D%28./1534490558916.png%29%0A%0A%23%23%23%20Implementation%20Example%20%28Inverted%20Dropout%29%0A%u8FD9%u662F%u6700%u5E38%u89C1%u7684Dropout%u5B9E%u73B0%u65B9%u6CD5%uFF0C%u53EB%22Inverted%20Dropout%22%20%28%u53CD%u5411%u968F%u673ADropout%29%u3002%u8BA1%u7B97%u6B65%u9AA4%u5982%u4E0B%uFF1A%0A%60%60%60python%0Ad3%20%3D%20np.random.rand%28a3.shape%5B0%5D%2C%20a3.shape%5B1%5D%29%20%3C%20keep-prob%0Aa3%20%3D%20np.multiply%28a3%2C%20d3%29%0Aa3%20/%3D%20keep-prob%0A%60%60%60%0A%u89E3%u91CA%u4E00%u4E0B%uFF1A%0A1.%20keep-prob%u4EE3%u8868%u4FDD%u7559hidden%20unit%u7684%u6982%u7387%u3002%u5982%u679Ckeep-prob%20%3D%200.8%uFF0C%u5219%u670980%25%u7684unit%u88AB%u4FDD%u7559%uFF0C20%25%u7684unit%u88AB%u5220%u9664%0A2.%20%u4E4B%u6240%u4EE5%u6700%u540E%u4E00%u884C%u8981re-scale%uFF0C%u56E0%u4E3Aa3%u88AB%u5220%u9664%u6389%u4E00%u4E9Bunit%uFF0C%u4ED6%u7684%u671F%u671B%u503C%u5C31%u53EA%u6709%u539F%u5148%u7684keep-prob%u7684%u6BD4%u4F8B%uFF0C%u6240%u4EE5%u8FD9%u91CC%u9700%u8981re-scale%uFF0C%u8FD9%u6837%u5728%u9A8C%u8BC1test%20set%u7684%u65F6%u5019%u4E0D%u4F1A%u6709scaling%u7684%u95EE%u9898%0A3.%20%u6CE8%u610F%uFF1A%u7B2C%u4E00%u884C%u7528%u7684%u662F%60np.random.rand%60%u800C%u4E0D%u662F%60np.random.randn%60%u3002%u56E0%u4E3A%60randn%60%u83B7%u53D6%u7684%u968F%u673A%u6570%u662F%u6B63%u6001%u5206%u6B65%uFF0C%u6240%u4EE5%u5E76%u4E0D%u80FD%u4FDD%u8BC1%u5C0F%u4E8E%60keep-prob%60%u7684%u6982%u7387%u4E3A%60keep-prob%60%u3002%60rand%60%u4EA7%u751F%u7684%u662F%u5747%u5300%u5206%u6B65%uFF0C%u5219%u80FD%u4FDD%u8BC1%u3002%0A%23%23%23%20Make%20Prediction%20at%20Test%20Time%0A%u9A8C%u8BC1%u7684%u65F6%u5019%uFF0C%u4E0D%u4F7F%u7528Dropout%u3002%u56E0%u4E3A%u5F15%u5165Dropout%u5C31%u662F%u5F15%u5165%u968F%u673A%u566A%u58F0%uFF0C%u4F1A%u5BFC%u81F4%u9884%u6D4B%u503C%u5373%24%5Chat%20y%24%u4E0D%u7A33%u5B9A%u3002%u6240%u4EE5%u9A8C%u8BC1%u65F6%u901A%u5E38%u4E0D%u7528Dropout%u3002%0A%21%5BAlt%20text%7C350x0%5D%28./1534496834899.png%29%0A%0A%23%23%20Other%20Regularization%0A-%20Augment%20data%20set.%0A%09-%20%u5C06%u539F%u6709%u56FE%u7247%u8FDB%u884C%u5904%u7406%u5F97%u5230%u66F4%u5927%u7684training%20set%u6765%u6D88%u9664variance%u3002%u4F8B%u5982%u65CB%u8F6C%uFF0C%u53CD%u8F6C%u56FE%u7247%0A-%20Early%20Stopping%0A%09-%20%u5728variance%u95EE%u9898%u8FD8%u4E0D%u662F%u5F88%u660E%u663E%u7684%u65F6%u5019stop%uFF0C%u770B%u4E0B%u56FE%uFF0C%u5728%u4E2D%u95F4%u7684%u70B9%u5904%u5C31%u505C%u6B62%u8FED%u4EE3%u3002%0A%21%5BAlt%20text%7C500x0%5D%28./1534497836025.png%29%0A%0A%23%23%20Vanishing/Exploding%20Gradients%0A%u68AF%u5EA6%u6D88%u5931%u548C%u68AF%u5EA6%u7206%u70B8%u3002%u8FD9%u662F%u4E3A%u4EC0%u4E48%u795E%u7ECF%u7F51%u7EDC%u4E3A%u4EC0%u4E48%u4E0D%u80FD%u5F88%u6DF1%u3002%0A%21%5BAlt%20text%5D%28./1534498747912.png%29%0A%0A%u4EE5%u8FD9%u6837%u7684%u7F51%u7EDC%u4E3E%u4F8B%u3002%u91C7%u7528%u7EBF%u6027%u6FC0%u6D3B%u51FD%u6570%uFF0C%u5373g%28z%29%3Dz%uFF0C%u5219%0A%24%24%5Chat%20y%3Dw%5E%7B%5Bl%5D%7Dw%5E%7B%5Bl-1%5D%7D%5Cdots%20w%5E1x%24%24%0A%24%5Cfrac%7B%5Cpartial%20J%7D%7Bw%5E%7B%5Bl%5D%7D%7D%24%u6B63%u6BD4%u4E8E%24w%5E%7B%5Bl-1%5D%7D%5Cdots%20w%5E1x%24%uFF0C%u5982%u679Cw%u4E2D%u6709%u5C0F%u4E8E1%u7684%u6570%uFF0C%u4E58n%u6B21%u540E%u5C31%u4F1A%u63A5%u8FD1%u4E8E0%uFF0C%u6B64%u4E3A%u68AF%u5EA6%u6D88%u5931%uFF0C%u53CD%u4E4B%u5219%u4E3A%u68AF%u5EA6%u7206%u70B8%u3002%u81F3%u4ECA%u4ECD%u6CA1%u6709%u5F88%u597D%u7684%u529E%u6CD5%u53EF%u4EE5%u6D88%u9664%u8FD9%u4E24%u79CD%u95EE%u9898%u3002%u4F46%u662F%u53EF%u4EE5%u901A%u8FC7%u968F%u673A%u521D%u59CB%u5316%u6743%u91CD%u77E9%u9635%u7684%u65B9%u5F0F%u6765%u6539%u8FDB%u3002%u5177%u4F53%u505A%u6CD5%u5982%u4E0B%uFF1A%0A%21%5BAlt%20text%7C250x0%5D%28./1534546536710.png%29%0A%u5BF9%u4E8E%u8FD9%u6837%u4E00%u4E2A%u5355%u5C42%u7F51%u7EDC%uFF0C%u5E76%u91C7%u7528%u7EBF%u6027%u6FC0%u6D3B%u51FD%u6570%uFF0C%u6709%24z%3Dw_1x_1%20+%20w_2x_2+%5Cdots+w_nx_n%24%uFF0Cn%u8D8A%u5927%u5219%u5E0C%u671B%u6BCF%u4E00%u9879%u90FD%u8D8A%u5C0F%uFF0C%u6240%u4EE5%u5E0C%u671B%u65B9%u5DEE%u503C%u4E3A%24Var%28w_i%29%20%3D%20%5Cfrac%20%7B1%7D%7Bn%7D%24%u3002%u6240%u4EE5%u968F%u673A%u521D%u59CB%u5316w%u65F6%u53EF%u4EE5%u5982%u4E0B%uFF1A%0A%24%24w%5E%7B%5Bl%5D%7D%20%3D%20%5Cmathtt%7Bnp.random.rand%28shape%29%7D%20%5Cast%20%5Cmathtt%7Bnp.sqrt%7D%28%5Cfrac%20%7B1%7D%7Bn%5E%7B%5Bl-1%5D%7D%7D%29%20%5Ctag%202%24%24%0A%u5F53%u91C7%u7528ReLU%u6FC0%u6D3B%u51FD%u6570%u65F6%uFF0C%u671F%u671B%u65B9%u5DEE%u4E3A%24Var%28w_i%29%20%3D%20%5Cfrac%20%7B2%7D%7Bn%7D%24%uFF0C%282%29%u5F0F%u4E2D%u7684%u5E38%u6570%u53D8%u62102%u5373%u53EF%uFF1A%0A%24%24w%5E%7B%5Bl%5D%7D%20%3D%20%5Cmathtt%7Bnp.random.rand%28shape%29%7D%20%5Cast%20%5Cmathtt%7Bnp.sqrt%7D%28%5Cfrac%20%7B2%7D%7Bn%5E%7B%5Bl-1%5D%7D%7D%29%20%5Ctag%203%24%24%0A%u5F53%u91C7%u7528tanh%u6FC0%u6D3B%u51FD%u6570%u65F6%uFF0C%u516C%u5F0F%u540C%282%29%u3002%0A%282%29%u5F0F%u4E2D%u7684%u5E73%u65B9%u9879%u53C8%u53EBXavier%20Initialization%uFF0C%u5373%24%5Csqrt%20%7B%5Cfrac%20%7B1%7D%7Bn%5E%7B%5Bl-1%5D%7D%7D%7D%24%0A%283%29%u5F0F%u4E2D%u7684%u5E73%u65B9%u9879%u53EBHe%20Initialization%uFF0C%u5373%24%5Csqrt%20%7B%5Cfrac%20%7B2%7D%7Bn%5E%7B%5Bl-1%5D%7D%7D%7D%24%0A%0A%3E**Conclusion%20for%20random%20weight%20initialization**%0A-%20Different%20initializations%20lead%20to%20different%20results%0A-%20Random%20initialization%20is%20used%20to%20break%20symmetry%20and%20make%20sure%20different%20hidden%20units%20can%20learn%20different%20things%0A-%20Don%27t%20intialize%20to%20values%20that%20are%20too%20large%0A-%20He%20initialization%20works%20well%20for%20networks%20with%20ReLU%20activations.

Edit

2016年在做微信打印Android agent app的时候,研究过如何在开发Android app的时候TDD。详细参考此篇博文Android单元测试
当时的最终方案是:Powermock + Mockito + JUnit做local test。因为要Mock各种Android SDK中的类,所以有一种被无力控制的恐惧。所以在做Niwatori的时候,迟迟没有开展TDD。因为最近添加的功能稍微有点复杂了,感觉各种不顺,所以考虑重新拾起TDD。于是有了各种折腾,并验证了之前无力的恐惧后的这一篇。不过结果好的是看起来找到了一条Android app TDD开发不错的路子。

这一切都要归功于

Roboletric

起初的相识还是在Android developer官网关于测试的页面。然后在搜索Powermock用法的时候,看到很多帖子都提到了roboletric。因为认识到Mockito + Powermock的弱点(如下),所以决定转向roboletric。

Mockito

  • 不能mock final class/method
  • 不能mock private/static

Powermock

  • 需要自己mock各种class,当函数大了的时候,因为会引用非常多的Android类,所以会让人感到很无力

在编译Android app的时候,Android SDK以android.jar的形式参与编译。而这个android.jar中的各个类并没有具体的实现,只是一个stub。所以如果不经过mock就直接在Unit Test中使用Android类就会出现Error java.lang.RuntimeException: Stub!错误。
Roboletric就是为了消除这种错误诞生的。它为所有的Android类定义了可以跑在PC端JVM下的class。而且提供了很多额外的功能,方便开发者做隔离测试以及UI方面的测试。

入门

首先推荐的还是官网主页。然后还有几个不错的中文帖子:

对于配置环境和第一个简单的实例,最好是按照官网的步骤去做。因为在setup的时候,往往有很多版本号依赖要处理,尤其是这种出身社区的框架。往往依赖处理不是特别好。

Powermock + Roboletric

用上Roboletric以后,你会发现原先需要各种mock的函数,现在不用怎么mock就能编过了,甚至有些listener都能起作用。但是因为Roboletric本身只是提供Android SDK的副本,对于测试并不是那么在行,或者说其目的并不是一个更power的mock库。当我们需要为某些class提供预设的功能,异或需要对某些对象调用次数进行verify的时候,还是需要powermock的(或者Mockito,但鉴于其功能实在太low,能用Powermock的就用Powermock吧)。
入门参看Roboletric GitHub wiki:Using PowerMock。示例如下:

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class)
@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
@PrepareForTest(Static.class)
public class DeckardActivityTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
@Test
public void testStaticMocking() {
PowerMockito.mockStatic(Static.class);
Mockito.when(Static.staticMethod()).thenReturn("hello mock");
assertTrue(Static.staticMethod().equals("hello mock"));
}
}

特别要注意的是:

  1. 因为class开头用了@RunWith(RobolectricTestRunner.class)标注,所以无法用PowermockTestRunner.class。所以必须加上下面两行:
@Rule
public PowerMockRule rule = new PowerMockRule();

否则会出现各种Powermock无法工作的异常,例如class没有prepare啦,不能mock private函数等等。

  1. 因为Roboletric提供了很多Shadow类,而这些类和mock有冲突。例如Intent intent = mock(Intent.class)就会导致这个莫名其妙的错误。

java.lang.LinkageError: loader constraint violation: loader (instance of net/bytebuddy/dynamic/loading/MultipleParentClassLoader) previously initiated loading for a different type with name "org/xmlpull/v1/XmlSerializer

所以就要加上@PowerMockIgnore。甚至Ignore的列表要更长,例如:

@PowerMockIgnore({
"org.mockito.*",
"org.robolectric.*",
"android.*",
"javax.xml.*",
"org.xml.sax.*",
"org.w3c.dom.*",
"org.springframework.context.*",
"org.apache.log4j.*"
})

踩坑列表

PowerMockito.whenNew is not working

You need to put the class where the constructor is called into the @PrepareForTest annotation instead of the class which is being constructed - see Mock construction of new objects.

总结

用Roboletric来解决Android SDK问题,用Powermock+JUnit来解决unit test问题。

%23%20Android%u5355%u5143%u6D4B%u8BD5%28%u4E8C%29%20-%20Roboletric%20+%20Powermock%0A@%28myblog%29%5BAndroid%2C%20unittest%5D%0A%0A2016%u5E74%u5728%u505A%u5FAE%u4FE1%u6253%u5370Android%20agent%20app%u7684%u65F6%u5019%uFF0C%u7814%u7A76%u8FC7%u5982%u4F55%u5728%u5F00%u53D1Android%20app%u7684%u65F6%u5019TDD%u3002%u8BE6%u7EC6%u53C2%u8003%u6B64%u7BC7%u535A%u6587%5BAndroid%u5355%u5143%u6D4B%u8BD5%5D%28https%3A//zhougy0717.github.io/2016/10/19/Android%25E5%258D%2595%25E5%2585%2583%25E6%25B5%258B%25E8%25AF%2595/%29%u3002%0A%u5F53%u65F6%u7684%u6700%u7EC8%u65B9%u6848%u662F%uFF1APowermock%20+%20Mockito%20+%20JUnit%u505A%5Blocal%20test%5D%28https%3A//developer.android.com/training/testing/unit-testing/local-unit-tests.html%29%u3002%u56E0%u4E3A%u8981Mock%u5404%u79CDAndroid%20SDK%u4E2D%u7684%u7C7B%uFF0C%u6240%u4EE5%u6709%u4E00%u79CD%u88AB%u65E0%u529B%u63A7%u5236%u7684%u6050%u60E7%u3002%u6240%u4EE5%u5728%u505ANiwatori%u7684%u65F6%u5019%uFF0C%u8FDF%u8FDF%u6CA1%u6709%u5F00%u5C55TDD%u3002%u56E0%u4E3A%u6700%u8FD1%u6DFB%u52A0%u7684%u529F%u80FD%u7A0D%u5FAE%u6709%u70B9%u590D%u6742%u4E86%uFF0C%u611F%u89C9%u5404%u79CD%u4E0D%u987A%uFF0C%u6240%u4EE5%u8003%u8651%u91CD%u65B0%u62FE%u8D77TDD%u3002%u4E8E%u662F%u6709%u4E86%u5404%u79CD%u6298%u817E%uFF0C%u5E76%u9A8C%u8BC1%u4E86%u4E4B%u524D%u65E0%u529B%u7684%u6050%u60E7%u540E%u7684%u8FD9%u4E00%u7BC7%u3002%u4E0D%u8FC7%u7ED3%u679C%u597D%u7684%u662F%u770B%u8D77%u6765%u627E%u5230%u4E86%u4E00%u6761Android%20app%20TDD%u5F00%u53D1%u4E0D%u9519%u7684%u8DEF%u5B50%u3002%0A%0A%u8FD9%u4E00%u5207%u90FD%u8981%u5F52%u529F%u4E8E%0A%23%23%20Roboletric%0A%u8D77%u521D%u7684%u76F8%u8BC6%u8FD8%u662F%u5728%5BAndroid%20developer%u5B98%u7F51%u5173%u4E8E%u6D4B%u8BD5%u7684%u9875%u9762%5D%28https%3A//developer.android.com/training/testing/fundamentals.html%29%u3002%u7136%u540E%u5728%u641C%u7D22Powermock%u7528%u6CD5%u7684%u65F6%u5019%uFF0C%u770B%u5230%u5F88%u591A%u5E16%u5B50%u90FD%u63D0%u5230%u4E86roboletric%u3002%u56E0%u4E3A%u8BA4%u8BC6%u5230Mockito%20+%20Powermock%u7684%u5F31%u70B9%28%u5982%u4E0B%29%uFF0C%u6240%u4EE5%u51B3%u5B9A%u8F6C%u5411roboletric%u3002%0A%3E%20Mockito%0A%3E%20-%20%u4E0D%u80FDmock%20final%20class/method%0A%3E%20-%20%u4E0D%u80FDmock%20private/static%0A%0A%3E%20Powermock%0A%3E%20-%20%u9700%u8981%u81EA%u5DF1mock%u5404%u79CDclass%uFF0C%u5F53%u51FD%u6570%u5927%u4E86%u7684%u65F6%u5019%uFF0C%u56E0%u4E3A%u4F1A%u5F15%u7528%u975E%u5E38%u591A%u7684Android%u7C7B%uFF0C%u6240%u4EE5%u4F1A%u8BA9%u4EBA%u611F%u5230%u5F88%u65E0%u529B%0A%0A%u5728%u7F16%u8BD1Android%20app%u7684%u65F6%u5019%uFF0CAndroid%20SDK%u4EE5android.jar%u7684%u5F62%u5F0F%u53C2%u4E0E%u7F16%u8BD1%u3002%u800C%u8FD9%u4E2Aandroid.jar%u4E2D%u7684%u5404%u4E2A%u7C7B%u5E76%u6CA1%u6709%u5177%u4F53%u7684%u5B9E%u73B0%uFF0C%u53EA%u662F%u4E00%u4E2Astub%u3002%u6240%u4EE5%u5982%u679C%u4E0D%u7ECF%u8FC7mock%u5C31%u76F4%u63A5%u5728Unit%20Test%u4E2D%u4F7F%u7528Android%u7C7B%u5C31%u4F1A%u51FA%u73B0%60Error%20java.lang.RuntimeException%3A%20Stub%21%60%u9519%u8BEF%u3002%0ARoboletric%u5C31%u662F%u4E3A%u4E86%u6D88%u9664%u8FD9%u79CD%u9519%u8BEF%u8BDE%u751F%u7684%u3002%u5B83%u4E3A%u6240%u6709%u7684Android%u7C7B%u5B9A%u4E49%u4E86%u53EF%u4EE5%u8DD1%u5728PC%u7AEFJVM%u4E0B%u7684class%u3002%u800C%u4E14%u63D0%u4F9B%u4E86%u5F88%u591A%u989D%u5916%u7684%u529F%u80FD%uFF0C%u65B9%u4FBF%u5F00%u53D1%u8005%u505A%u9694%u79BB%u6D4B%u8BD5%u4EE5%u53CAUI%u65B9%u9762%u7684%u6D4B%u8BD5%u3002%0A%0A%23%23%23%20%u5165%u95E8%0A%u9996%u5148%u63A8%u8350%u7684%u8FD8%u662F%5B%u5B98%u7F51%u4E3B%u9875%5D%28http%3A//robolectric.org/%29%u3002%u7136%u540E%u8FD8%u6709%u51E0%u4E2A%u4E0D%u9519%u7684%u4E2D%u6587%u5E16%u5B50%uFF1A%0A-%20%5BRobolectric%u4F7F%u7528%u6559%u7A0B%5D%28http%3A//www.cnblogs.com/slgkaifa/p/7354609.html%29%3A%20%u53EF%u4EE5%u53C2%u8003Properties%u6587%u4EF6%u4EE5%u53CAActivity%u751F%u547D%u5468%u671F%u90E8%u5206%u3002%0A-%20%5BAndroid%u5355%u5143%u6D4B%u8BD5%u4E4BRobolectric%u6846%u67B6%5D%28https%3A//maxwell-nc.github.io/android/robolectricTest.html%29%3A%20%u53EF%u4EE5%u53C2%u8003Robolectric%u914D%u7F6E%u4EE5%u53CA%u9488%u5BF9%u5404%u79CDAndroid%u7EC4%u4EF6%u7684%u6D4B%u8BD5%u65B9%u6CD5%u90E8%u5206%u3002%0A%0A%u5BF9%u4E8E%u914D%u7F6E%u73AF%u5883%u548C%u7B2C%u4E00%u4E2A%u7B80%u5355%u7684%u5B9E%u4F8B%uFF0C%u6700%u597D%u662F%u6309%u7167%u5B98%u7F51%u7684%u6B65%u9AA4%u53BB%u505A%u3002%u56E0%u4E3A%u5728setup%u7684%u65F6%u5019%uFF0C%u5F80%u5F80%u6709%u5F88%u591A%u7248%u672C%u53F7%u4F9D%u8D56%u8981%u5904%u7406%uFF0C%u5C24%u5176%u662F%u8FD9%u79CD%u51FA%u8EAB%u793E%u533A%u7684%u6846%u67B6%u3002%u5F80%u5F80%u4F9D%u8D56%u5904%u7406%u4E0D%u662F%u7279%u522B%u597D%u3002%0A%0A%23%23%20Powermock%20+%20Roboletric%0A%u7528%u4E0ARoboletric%u4EE5%u540E%uFF0C%u4F60%u4F1A%u53D1%u73B0%u539F%u5148%u9700%u8981%u5404%u79CDmock%u7684%u51FD%u6570%uFF0C%u73B0%u5728%u4E0D%u7528%u600E%u4E48mock%u5C31%u80FD%u7F16%u8FC7%u4E86%uFF0C%u751A%u81F3%u6709%u4E9Blistener%u90FD%u80FD%u8D77%u4F5C%u7528%u3002%u4F46%u662F%u56E0%u4E3ARoboletric%u672C%u8EAB%u53EA%u662F%u63D0%u4F9BAndroid%20SDK%u7684%u526F%u672C%uFF0C%u5BF9%u4E8E%u6D4B%u8BD5%u5E76%u4E0D%u662F%u90A3%u4E48%u5728%u884C%uFF0C%u6216%u8005%u8BF4%u5176%u76EE%u7684%u5E76%u4E0D%u662F%u4E00%u4E2A%u66F4power%u7684mock%u5E93%u3002%u5F53%u6211%u4EEC%u9700%u8981%u4E3A%u67D0%u4E9Bclass%u63D0%u4F9B%u9884%u8BBE%u7684%u529F%u80FD%uFF0C%u5F02%u6216%u9700%u8981%u5BF9%u67D0%u4E9B%u5BF9%u8C61%u8C03%u7528%u6B21%u6570%u8FDB%u884Cverify%u7684%u65F6%u5019%uFF0C%u8FD8%u662F%u9700%u8981powermock%u7684%uFF08%u6216%u8005Mockito%uFF0C%u4F46%u9274%u4E8E%u5176%u529F%u80FD%u5B9E%u5728%u592Alow%uFF0C%u80FD%u7528Powermock%u7684%u5C31%u7528Powermock%u5427%uFF09%u3002%0A%u5165%u95E8%u53C2%u770BRoboletric%20GitHub%20wiki%uFF1A%5BUsing%20PowerMock%5D%28https%3A//github.com/robolectric/robolectric/wiki/Using-PowerMock%29%u3002%u793A%u4F8B%u5982%u4E0B%uFF1A%0A%60%60%60java%0A@RunWith%28RobolectricTestRunner.class%29%0A@Config%28constants%20%3D%20BuildConfig.class%29%0A@PowerMockIgnore%28%7B%20%22org.mockito.*%22%2C%20%22org.robolectric.*%22%2C%20%22android.*%22%20%7D%29%0A@PrepareForTest%28Static.class%29%0Apublic%20class%20DeckardActivityTest%20%7B%0A%0A%20%20%20%20@Rule%0A%20%20%20%20public%20PowerMockRule%20rule%20%3D%20new%20PowerMockRule%28%29%3B%0A%0A%20%20%20%20@Test%0A%20%20%20%20public%20void%20testStaticMocking%28%29%20%7B%0A%20%20%20%20%20%20%20%20PowerMockito.mockStatic%28Static.class%29%3B%0A%20%20%20%20%20%20%20%20Mockito.when%28Static.staticMethod%28%29%29.thenReturn%28%22hello%20mock%22%29%3B%0A%0A%20%20%20%20%20%20%20%20assertTrue%28Static.staticMethod%28%29.equals%28%22hello%20mock%22%29%29%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%u7279%u522B%u8981%u6CE8%u610F%u7684%u662F%uFF1A%0A1.%20%u56E0%u4E3Aclass%u5F00%u5934%u7528%u4E86%60@RunWith%28RobolectricTestRunner.class%29%60%u6807%u6CE8%uFF0C%u6240%u4EE5%u65E0%u6CD5%u7528%60PowermockTestRunner.class%60%u3002%u6240%u4EE5%u5FC5%u987B%u52A0%u4E0A%u4E0B%u9762%u4E24%u884C%uFF1A%0A%60%60%60%0A@Rule%0Apublic%20PowerMockRule%20rule%20%3D%20new%20PowerMockRule%28%29%3B%0A%60%60%60%0A%u5426%u5219%u4F1A%u51FA%u73B0%u5404%u79CDPowermock%u65E0%u6CD5%u5DE5%u4F5C%u7684%u5F02%u5E38%uFF0C%u4F8B%u5982class%u6CA1%u6709prepare%u5566%uFF0C%u4E0D%u80FDmock%20private%u51FD%u6570%u7B49%u7B49%u3002%0A%0A2.%20%u56E0%u4E3ARoboletric%u63D0%u4F9B%u4E86%u5F88%u591AShadow%u7C7B%uFF0C%u800C%u8FD9%u4E9B%u7C7B%u548Cmock%u6709%u51B2%u7A81%u3002%u4F8B%u5982%60Intent%20intent%20%3D%20mock%28Intent.class%29%60%u5C31%u4F1A%u5BFC%u81F4%u8FD9%u4E2A%u83AB%u540D%u5176%u5999%u7684%u9519%u8BEF%u3002%0A%0A%3E%60java.lang.LinkageError%3A%20loader%20constraint%20violation%3A%20loader%20%28instance%20of%20net/bytebuddy/dynamic/loading/MultipleParentClassLoader%29%20previously%20initiated%20loading%20for%20a%20different%20type%20with%20name%20%22org/xmlpull/v1/XmlSerializer%60%0A%0A%u6240%u4EE5%u5C31%u8981%u52A0%u4E0A%60@PowerMockIgnore%60%u3002%u751A%u81F3Ignore%u7684%u5217%u8868%u8981%u66F4%u957F%uFF0C%u4F8B%u5982%uFF1A%0A%60%60%60%0A@PowerMockIgnore%28%7B%20%0A%09%22org.mockito.*%22%2C%20%0A%09%22org.robolectric.*%22%2C%20%0A%09%22android.*%22%2C%0A%09%22javax.xml.*%22%2C%20%0A%09%22org.xml.sax.*%22%2C%20%0A%09%22org.w3c.dom.*%22%2C%20%20%0A%09%22org.springframework.context.*%22%2C%20%0A%09%22org.apache.log4j.*%22%20%0A%7D%29%0A%60%60%60%0A%0A%23%23%20%u8E29%u5751%u5217%u8868%0A%23%23%23%20PowerMockito.whenNew%20is%20not%20working%0A%3EYou%20need%20to%20put%20the%20class%20**where%20the%20constructor%20is%20called**%20into%20the%20@PrepareForTest%20annotation%20instead%20of%20the%20class%20which%20is%20being%20constructed%20-%20see%20Mock%20construction%20of%20new%20objects.%0A%0A%23%23%20%u603B%u7ED3%0A%u7528Roboletric%u6765%u89E3%u51B3Android%20SDK%u95EE%u9898%uFF0C%u7528Powermock+JUnit%u6765%u89E3%u51B3unit%20test%u95EE%u9898%u3002

Edit

问题描述

Evaluation Orders and Disorders

// Example 1(a)
//
f( expr1, expr2 );
// Example 1(b)
//
f( g( expr1 ), h( expr2 ) );

编译器只要满足下面的规则,为了便于优化执行顺序,而C++标准并不要求具体指令顺序:

  1. expr1在g执行之前完成,expr2在h执行之前完成
  2. g, h在f执行之前完成

首先,在函数正式执行之前,所有的Expression Evaluation要完成。
其次,有可能出现乱序。
所以有可能出现下面的执行顺序:
顺序一

  • expr1
  • expr2
  • g
  • h

顺序二

  • expr1
  • g
  • expr2
  • h

上面两种情况都符合。

Exception Safety Problems

当C++编译器调用new操作符的时候会做两件事:1. 开辟内存,2. 调用类构造函数。所以下面的code如果处理得当,是不会有内存泄漏:

T1* t1 = new T1;
T2* t2 = new T2;

当T1构造函数出现异常时,相应的内存会被释放掉。当T2构造函数出现异常时,T2的内存会被释放,T1的内存也有机会被释放。(解决方法是在两条语句之间加上异常处理,当然用smart pointer也可以解决问题。后面会阐述smart pointer的方法)

但是在遇到Expression Evaluation的时候,情况会变得复杂:

// In some header file:
void f( T1*, T2* );
// In some implementation file:
f( new T1, new T2 );
  • T2构造函数异常时,根本没有机会释放T1的内存。用异常处理也没办法,因为T1的内存开辟出来赋值给了一个临时变量。而这个变量的有效期就只在那个括号里。
  • 乱序让问题更加复杂,因为你不知道是T1先构造还是T2先构造,你不知道是下面的哪种顺序,但是每一种顺序都有问题。所以无从下手。
    • 顺序一
      • 1: allocate memory for T1
        2: construct T1
        3: allocate memory for T2
        4: construct T2
        5: call f()
    • 顺序二
      • 1: allocate memory for T1
        2: allocate memory for T2
        3: construct T1
        4: construct T2
        5: call f()

解决方案

看起来像的解决方案

用auto_ptr

// In some header file:
void f( auto_ptr<T1>, auto_ptr<T2> );
// In some implementation file:
f( auto_ptr<T1>( new T1 ), auto_ptr<T2>( new T2 ) );

看起来用了smart pointer,应该不存在释放内存的问题了。但其实并没有改善,因为乱序问题,你没法保证auto_ptr<T1>new T2之前调用。如果T2构造失败了,new T1的内存就泄露了。Vice versa。

用参数默认值

// In some header file:
void f( auto_ptr<T1> = auto_ptr<T1>( new T1 ),
auto_ptr<T2> = auto_ptr<T1>( new T2 ) );
// In some implementation file:
f();

没有本质的改善。因为虽然参数默认值是在函数声明中,但是那些newauto_ptr<>是在执行时才会去做的事情。一样会有乱序。

真正的解决方案

// In some header file (same as in Example 2b):
void f( auto_ptr<T1>, auto_ptr<T2> );
// In some implementation file:
f( auto_ptr_new<T1>(), auto_ptr_new<T2>() );

看起来和之前的假解决方案很像对不对,区别是相应的newauto_ptr<>构造函数放到一起了。这样不管是auto_ptr_new<T1>()在前,还是auto_ptr_new<T2>()在前,都不会引起Exception Safety问题。

这个方案也就是网上经常有人问到的“为什么要用make_xxx_ptr,而不用new xxx_ptr?”的原因之一,xxx_ptr可以是任何的smart pointer(包括但不限于:auto_ptr, shared_ptr, unique_ptr):

  • 可以避免Exception Safety问题
  • 避免显示使用new运算符,避免潜在问题
  • 局限是只能用默认构造函数,而无法使用带参数构造函数

下面也是一个办法:

// In some header file:
void f( auto_ptr<T1>, auto_ptr<T2> );
// In some implementation file:
{
auto_ptr<T1> t1( new T1 );
f( t1, auto_ptr<T2>( new T2 ) );
}

这个方法更好:

// In some header file:
void f( auto_ptr<T1>, auto_ptr<T2> );
// In some implementation file:
{
auto_ptr<T1> t1( new T1 );
auto_ptr<T2> t2( new T2 );
f( t1, t2 );
}

总结

Exception-Safe Function Calls作者的guide lines作总结:

Perform every resource allocation (e.g., new) in its own code statement which immediately gives the new resource to a manager object (e.g., auto_ptr).

意思是一行就只分配一个资源,并且立即将该资源交给smart pointer管理。

参考文献

Exception-Safe Function Calls
GotW #89 Solution: Smart Pointer

%23%20Exception%20Safety%20issue%0A@%28myblog%29%5Bc/c++%5D%0A%0A%23%23%20%u95EE%u9898%u63CF%u8FF0%0A%23%23%23%20Evaluation%20Orders%20and%20Disorders%0A%60%60%60%0A//%20%20Example%201%28a%29%0A//%0Af%28%20expr1%2C%20expr2%20%29%3B%0A//%20%20Example%201%28b%29%0A//%0Af%28%20g%28%20expr1%20%29%2C%20h%28%20expr2%20%29%20%29%3B%0A%60%60%60%0A%3E%20%u7F16%u8BD1%u5668%u53EA%u8981%u6EE1%u8DB3%u4E0B%u9762%u7684%u89C4%u5219%uFF0C%u4E3A%u4E86%u4FBF%u4E8E%u4F18%u5316%u6267%u884C%u987A%u5E8F%uFF0C%u800CC++%u6807%u51C6%u5E76%u4E0D%u8981%u6C42%u5177%u4F53%u6307%u4EE4%u987A%u5E8F%uFF1A%0A%3E%201.%20expr1%u5728g%u6267%u884C%u4E4B%u524D%u5B8C%u6210%uFF0Cexpr2%u5728h%u6267%u884C%u4E4B%u524D%u5B8C%u6210%0A%3E%202.%20g%2C%20h%u5728f%u6267%u884C%u4E4B%u524D%u5B8C%u6210%0A%0A%u9996%u5148%uFF0C%u5728%u51FD%u6570%u6B63%u5F0F%u6267%u884C%u4E4B%u524D%uFF0C%u6240%u6709%u7684Expression%20Evaluation%u8981%u5B8C%u6210%u3002%0A%u5176%u6B21%uFF0C%u6709%u53EF%u80FD%u51FA%u73B0%u4E71%u5E8F%u3002%0A%u6240%u4EE5%u6709%u53EF%u80FD%u51FA%u73B0%u4E0B%u9762%u7684%u6267%u884C%u987A%u5E8F%uFF1A%0A**%u987A%u5E8F%u4E00**%0A-%20expr1%0A-%20expr2%0A-%20g%0A-%20h%0A%0A**%u987A%u5E8F%u4E8C**%0A-%20expr1%0A-%20g%0A-%20expr2%0A-%20h%0A%0A%u4E0A%u9762%u4E24%u79CD%u60C5%u51B5%u90FD%u7B26%u5408%u3002%0A%0A%23%23%23%20Exception%20Safety%20Problems%0A%u5F53C++%u7F16%u8BD1%u5668%u8C03%u7528new%u64CD%u4F5C%u7B26%u7684%u65F6%u5019%u4F1A%u505A%u4E24%u4EF6%u4E8B%uFF1A1.%20%u5F00%u8F9F%u5185%u5B58%uFF0C2.%20%u8C03%u7528%u7C7B%u6784%u9020%u51FD%u6570%u3002%u6240%u4EE5%u4E0B%u9762%u7684code%u5982%u679C%u5904%u7406%u5F97%u5F53%uFF0C%u662F%u4E0D%u4F1A%u6709%u5185%u5B58%u6CC4%u6F0F%uFF1A%0A%60%60%60%0AT1*%20t1%20%3D%20new%20T1%3B%0AT2*%20t2%20%3D%20new%20T2%3B%0A%60%60%60%0A%u5F53T1%u6784%u9020%u51FD%u6570%u51FA%u73B0%u5F02%u5E38%u65F6%uFF0C%u76F8%u5E94%u7684%u5185%u5B58%u4F1A%u88AB%u91CA%u653E%u6389%u3002%u5F53T2%u6784%u9020%u51FD%u6570%u51FA%u73B0%u5F02%u5E38%u65F6%uFF0CT2%u7684%u5185%u5B58%u4F1A%u88AB%u91CA%u653E%uFF0CT1%u7684%u5185%u5B58%u4E5F%u6709%u673A%u4F1A%u88AB%u91CA%u653E%u3002%uFF08%u89E3%u51B3%u65B9%u6CD5%u662F%u5728%u4E24%u6761%u8BED%u53E5%u4E4B%u95F4%u52A0%u4E0A%u5F02%u5E38%u5904%u7406%uFF0C%u5F53%u7136%u7528smart%20pointer%u4E5F%u53EF%u4EE5%u89E3%u51B3%u95EE%u9898%u3002%u540E%u9762%u4F1A%u9610%u8FF0smart%20pointer%u7684%u65B9%u6CD5%uFF09%0A%0A%u4F46%u662F%u5728%u9047%u5230Expression%20Evaluation%u7684%u65F6%u5019%uFF0C%u60C5%u51B5%u4F1A%u53D8%u5F97%u590D%u6742%uFF1A%0A%60%60%60%0A//%20%20In%20some%20header%20file%3A%0Avoid%20f%28%20T1*%2C%20T2*%20%29%3B%0A//%20%20In%20some%20implementation%20file%3A%0Af%28%20new%20T1%2C%20new%20T2%20%29%3B%0A%60%60%60%0A-%20T2%u6784%u9020%u51FD%u6570%u5F02%u5E38%u65F6%uFF0C%u6839%u672C%u6CA1%u6709%u673A%u4F1A%u91CA%u653ET1%u7684%u5185%u5B58%u3002%u7528%u5F02%u5E38%u5904%u7406%u4E5F%u6CA1%u529E%u6CD5%uFF0C%u56E0%u4E3AT1%u7684%u5185%u5B58%u5F00%u8F9F%u51FA%u6765%u8D4B%u503C%u7ED9%u4E86%u4E00%u4E2A%u4E34%u65F6%u53D8%u91CF%u3002%u800C%u8FD9%u4E2A%u53D8%u91CF%u7684%u6709%u6548%u671F%u5C31%u53EA%u5728%u90A3%u4E2A%u62EC%u53F7%u91CC%u3002%0A-%20%u4E71%u5E8F%u8BA9%u95EE%u9898%u66F4%u52A0%u590D%u6742%uFF0C%u56E0%u4E3A%u4F60%u4E0D%u77E5%u9053%u662FT1%u5148%u6784%u9020%u8FD8%u662FT2%u5148%u6784%u9020%uFF0C%u4F60%u4E0D%u77E5%u9053%u662F%u4E0B%u9762%u7684%u54EA%u79CD%u987A%u5E8F%uFF0C%u4F46%u662F%u6BCF%u4E00%u79CD%u987A%u5E8F%u90FD%u6709%u95EE%u9898%u3002%u6240%u4EE5%u65E0%u4ECE%u4E0B%u624B%u3002%0A%09-%20%u987A%u5E8F%u4E00%0A%09%09-%201%3A%20allocate%20memory%20for%20T1%0A2%3A%20construct%20T1%0A3%3A%20allocate%20memory%20for%20T2%0A4%3A%20construct%20T2%0A5%3A%20call%20f%28%29%0A%09-%20%u987A%u5E8F%u4E8C%0A%09%09-%201%3A%20allocate%20memory%20for%20T1%0A2%3A%20allocate%20memory%20for%20T2%0A3%3A%20construct%20T1%0A4%3A%20construct%20T2%0A5%3A%20call%20f%28%29%0A%0A%0A%23%23%20%u89E3%u51B3%u65B9%u6848%0A%23%23%23%20%u770B%u8D77%u6765%u50CF%u7684%u89E3%u51B3%u65B9%u6848%0A%23%23%23%23%20%u7528auto_ptr%0A%60%60%60%0A//%20%20In%20some%20header%20file%3A%0Avoid%20f%28%20auto_ptr%3CT1%3E%2C%20auto_ptr%3CT2%3E%20%29%3B%0A//%20%20In%20some%20implementation%20file%3A%0Af%28%20auto_ptr%3CT1%3E%28%20new%20T1%20%29%2C%20auto_ptr%3CT2%3E%28%20new%20T2%20%29%20%29%3B%0A%60%60%60%0A%u770B%u8D77%u6765%u7528%u4E86smart%20pointer%uFF0C%u5E94%u8BE5%u4E0D%u5B58%u5728%u91CA%u653E%u5185%u5B58%u7684%u95EE%u9898%u4E86%u3002%u4F46%u5176%u5B9E%u5E76%u6CA1%u6709%u6539%u5584%uFF0C%u56E0%u4E3A%u4E71%u5E8F%u95EE%u9898%uFF0C%u4F60%u6CA1%u6CD5%u4FDD%u8BC1%60auto_ptr%3CT1%3E%60%u5728%60new%20T2%60%u4E4B%u524D%u8C03%u7528%u3002%u5982%u679CT2%u6784%u9020%u5931%u8D25%u4E86%uFF0C%60new%20T1%60%u7684%u5185%u5B58%u5C31%u6CC4%u9732%u4E86%u3002Vice%20versa%u3002%0A%0A%23%23%23%23%20%u7528%u53C2%u6570%u9ED8%u8BA4%u503C%0A%60%60%60%0A//%20%20In%20some%20header%20file%3A%0Avoid%20f%28%20auto_ptr%3CT1%3E%20%3D%20auto_ptr%3CT1%3E%28%20new%20T1%20%29%2C%0A%20%20%20%20%20%20%20%20auto_ptr%3CT2%3E%20%3D%20auto_ptr%3CT1%3E%28%20new%20T2%20%29%20%29%3B%0A//%20%20In%20some%20implementation%20file%3A%0Af%28%29%3B%0A%60%60%60%0A%u6CA1%u6709%u672C%u8D28%u7684%u6539%u5584%u3002%u56E0%u4E3A%u867D%u7136%u53C2%u6570%u9ED8%u8BA4%u503C%u662F%u5728%u51FD%u6570%u58F0%u660E%u4E2D%uFF0C%u4F46%u662F%u90A3%u4E9B%60new%60%u548C%60auto_ptr%3C%3E%60%u662F%u5728%u6267%u884C%u65F6%u624D%u4F1A%u53BB%u505A%u7684%u4E8B%u60C5%u3002%u4E00%u6837%u4F1A%u6709%u4E71%u5E8F%u3002%0A%0A%23%23%23%20%u771F%u6B63%u7684%u89E3%u51B3%u65B9%u6848%0A%60%60%60%0A//%20%20In%20some%20header%20file%20%28same%20as%20in%20Example%202b%29%3A%0Avoid%20f%28%20auto_ptr%3CT1%3E%2C%20auto_ptr%3CT2%3E%20%29%3B%0A//%20%20In%20some%20implementation%20file%3A%0Af%28%20auto_ptr_new%3CT1%3E%28%29%2C%20auto_ptr_new%3CT2%3E%28%29%20%29%3B%0A%60%60%60%0A%u770B%u8D77%u6765%u548C%u4E4B%u524D%u7684%u5047%u89E3%u51B3%u65B9%u6848%u5F88%u50CF%u5BF9%u4E0D%u5BF9%uFF0C%u533A%u522B%u662F%u76F8%u5E94%u7684%60new%60%u548C%60auto_ptr%3C%3E%60%u6784%u9020%u51FD%u6570%u653E%u5230%u4E00%u8D77%u4E86%u3002%u8FD9%u6837%u4E0D%u7BA1%u662F%60auto_ptr_new%3CT1%3E%28%29%60%u5728%u524D%uFF0C%u8FD8%u662F%60auto_ptr_new%3CT2%3E%28%29%60%u5728%u524D%uFF0C%u90FD%u4E0D%u4F1A%u5F15%u8D77Exception%20Safety%u95EE%u9898%u3002%0A%3E%u8FD9%u4E2A%u65B9%u6848%u4E5F%u5C31%u662F%u7F51%u4E0A%u7ECF%u5E38%u6709%u4EBA%u95EE%u5230%u7684%u201C%u4E3A%u4EC0%u4E48%u8981%u7528make%5C_xxx_ptr%uFF0C%u800C%u4E0D%u7528new%20xxx%5C_ptr%3F%u201D%u7684%u539F%u56E0%u4E4B%u4E00%uFF0Cxxx%5C_ptr%u53EF%u4EE5%u662F%u4EFB%u4F55%u7684smart%20pointer%uFF08%u5305%u62EC%u4F46%u4E0D%u9650%u4E8E%uFF1Aauto_ptr%2C%20shared_ptr%2C%20unique_ptr%uFF09%uFF1A%0A%3E-%20%u53EF%u4EE5%u907F%u514DException%20Safety%u95EE%u9898%0A%3E-%20%u907F%u514D%u663E%u793A%u4F7F%u7528%60new%60%u8FD0%u7B97%u7B26%uFF0C%u907F%u514D%u6F5C%u5728%u95EE%u9898%0A%3E-%20%u5C40%u9650%u662F%u53EA%u80FD%u7528%u9ED8%u8BA4%u6784%u9020%u51FD%u6570%uFF0C%u800C%u65E0%u6CD5%u4F7F%u7528%u5E26%u53C2%u6570%u6784%u9020%u51FD%u6570%0A%0A%u4E0B%u9762%u4E5F%u662F%u4E00%u4E2A%u529E%u6CD5%uFF1A%0A%60%60%60%0A//%20%20In%20some%20header%20file%3A%0Avoid%20f%28%20auto_ptr%3CT1%3E%2C%20auto_ptr%3CT2%3E%20%29%3B%0A//%20%20In%20some%20implementation%20file%3A%0A%7B%0A%20%20auto_ptr%3CT1%3E%20t1%28%20new%20T1%20%29%3B%0A%20%20f%28%20t1%2C%20auto_ptr%3CT2%3E%28%20new%20T2%20%29%20%29%3B%0A%7D%0A%60%60%60%0A%u8FD9%u4E2A%u65B9%u6CD5%u66F4%u597D%uFF1A%0A%60%60%60%0A//%20%20In%20some%20header%20file%3A%0Avoid%20f%28%20auto_ptr%3CT1%3E%2C%20auto_ptr%3CT2%3E%20%29%3B%0A//%20%20In%20some%20implementation%20file%3A%0A%7B%0A%20%20auto_ptr%3CT1%3E%20t1%28%20new%20T1%20%29%3B%0A%20%20auto_ptr%3CT2%3E%20t2%28%20new%20T2%20%29%3B%0A%20%20f%28%20t1%2C%20t2%20%29%3B%0A%7D%0A%60%60%60%0A%0A%23%23%20%u603B%u7ED3%0A%u4EE5%5BException-Safe%20Function%20Calls%5D%28http%3A//www.gotw.ca/gotw/056.htm%29%u4F5C%u8005%u7684guide%20lines%u4F5C%u603B%u7ED3%uFF1A%0A%3EPerform%20every%20resource%20allocation%20%28e.g.%2C%20new%29%20in%20its%20own%20code%20statement%20which%20immediately%20gives%20the%20new%20resource%20to%20a%20manager%20object%20%28e.g.%2C%20auto_ptr%29.%0A%0A%u610F%u601D%u662F%u4E00%u884C%u5C31%u53EA%u5206%u914D%u4E00%u4E2A%u8D44%u6E90%uFF0C%u5E76%u4E14%u7ACB%u5373%u5C06%u8BE5%u8D44%u6E90%u4EA4%u7ED9smart%20pointer%u7BA1%u7406%u3002%0A%0A%23%23%20%u53C2%u8003%u6587%u732E%0A%5BException-Safe%20Function%20Calls%5D%28http%3A//www.gotw.ca/gotw/056.htm%29%0A%5BGotW%20%2389%20Solution%3A%20Smart%20Pointer%5D%28https%3A//herbsutter.com/2013/05/29/gotw-89-solution-smart-pointers/%29

Edit

在C++中提供了按引用调用的方式,如下

class A{}
A& func(A& a)
{
A* b = new A();
b->param = a.param;
return *b;
}

引用既可以作为参数传递,也可以是返回值。所有的书上都提到引用即可视为对象的别名。他有如下特性:

  1. 可以像对象一样操作引用,使用"."操作符,而无需"->"操作符
  2. 其地址与引用的对象一致
  3. 所谓别名,就是引用已经与对象绑定,以下代码最后一行是不允许的。
A a;
A b;
A& c = a;
c = b;
  1. 引用是C++中的语法糖,其存在的目的就是让传递对象的时候更廉价一些,尽量避免调用构造函数。

作为参数

其实C++中不按引用传递自定义类对象参数也是可以的。如下:

class A{}
void func (A a);
void func (A& a);

两者均可以,区别在

  1. 前者传递时要分配一个临时变量,并调用A的拷贝构造函数。
  2. 前者在函数体内,对a的修改不会影响到外部a对象。这往往是我们想要的。所以,按引用调用的时候,往往更好的写法是:
void func (const A& a); // 用const来保证a对象不被修改

作为返回值

在定义运算符重载的时候,我们往往使用return *this;来保证链式调用,例如:

class A {
A& operator=(A& param){
...
return *this;
};
}
A a, b, c;
a = b = c;

如果不按引用返回,可以吗?

class A {
A operator=(A& param){
...
return *this;
};
}
A a, b, c;
a = b = c;

答案是也是可以的。区别是:

  • 不按引用传递时,b=c的操作返回时会先分配一个临时变量,以*this为参数调用A的拷贝构造函数,然后再调用一次A的拷贝构造函数将该临时变量作为结果传递给a=操作符函数。
  • 按引用传递,同样b=c返回时会分配一个临时变量,并调用A的拷贝构造函数,然后将该临时变量的引用值传给a=操作符函数。

可见虽然两者都能做到链式操作,但是按引用返回少调用了一次拷贝构造函数,效率提升。这与引用存在的价值也是一致的。

%23%20C++%u51FD%u6570%u4E2D%u7684%u6309%u5F15%u7528%u8C03%u7528%u4E0E%u8FD4%u56DE%0A@%28myblog%29%5Bc/c++%5D%0A%0A%u5728C++%u4E2D%u63D0%u4F9B%u4E86%u6309%u5F15%u7528%u8C03%u7528%u7684%u65B9%u5F0F%uFF0C%u5982%u4E0B%0A%60%60%60%0Aclass%20A%7B%7D%0AA%26%20func%28A%26%20a%29%0A%7B%0A%09A*%20b%20%3D%20new%20A%28%29%3B%0A%09b-%3Eparam%20%3D%20a.param%3B%0A%09return%20*b%3B%0A%7D%0A%60%60%60%0A%u5F15%u7528%u65E2%u53EF%u4EE5%u4F5C%u4E3A%u53C2%u6570%u4F20%u9012%uFF0C%u4E5F%u53EF%u4EE5%u662F%u8FD4%u56DE%u503C%u3002%u6240%u6709%u7684%u4E66%u4E0A%u90FD%u63D0%u5230%u5F15%u7528%u5373%u53EF%u89C6%u4E3A%u5BF9%u8C61%u7684%u522B%u540D%u3002%u4ED6%u6709%u5982%u4E0B%u7279%u6027%uFF1A%0A1.%20%u53EF%u4EE5%u50CF%u5BF9%u8C61%u4E00%u6837%u64CD%u4F5C%u5F15%u7528%uFF0C%u4F7F%u7528%60%22.%22%60%u64CD%u4F5C%u7B26%uFF0C%u800C%u65E0%u9700%60%22-%3E%22%60%u64CD%u4F5C%u7B26%0A2.%20%u5176%u5730%u5740%u4E0E%u5F15%u7528%u7684%u5BF9%u8C61%u4E00%u81F4%0A3.%20%u6240%u8C13%u522B%u540D%uFF0C%u5C31%u662F%u5F15%u7528%u5DF2%u7ECF%u4E0E%u5BF9%u8C61%u7ED1%u5B9A%uFF0C%u4EE5%u4E0B%u4EE3%u7801%u6700%u540E%u4E00%u884C%u662F%u4E0D%u5141%u8BB8%u7684%u3002%0A%60%60%60%0AA%20a%3B%0AA%20b%3B%0AA%26%20c%20%3D%20a%3B%0Ac%20%3D%20b%3B%0A%60%60%60%0A4.%20%u5F15%u7528%u662FC++%u4E2D%u7684%u8BED%u6CD5%u7CD6%uFF0C%u5176%u5B58%u5728%u7684%u76EE%u7684%u5C31%u662F%u8BA9%u4F20%u9012%u5BF9%u8C61%u7684%u65F6%u5019%u66F4%u5EC9%u4EF7%u4E00%u4E9B%uFF0C%u5C3D%u91CF%u907F%u514D%u8C03%u7528%u6784%u9020%u51FD%u6570%u3002%0A%0A%23%23%20%u4F5C%u4E3A%u53C2%u6570%0A%u5176%u5B9EC++%u4E2D%u4E0D%u6309%u5F15%u7528%u4F20%u9012%u81EA%u5B9A%u4E49%u7C7B%u5BF9%u8C61%u53C2%u6570%u4E5F%u662F%u53EF%u4EE5%u7684%u3002%u5982%u4E0B%uFF1A%0A%60%60%60%0Aclass%20A%7B%7D%0Avoid%20func%20%28A%20a%29%3B%0Avoid%20func%20%28A%26%20a%29%3B%0A%60%60%60%0A%u4E24%u8005%u5747%u53EF%u4EE5%uFF0C%u533A%u522B%u5728%0A1.%20%u524D%u8005%u4F20%u9012%u65F6%u8981%u5206%u914D%u4E00%u4E2A%u4E34%u65F6%u53D8%u91CF%uFF0C%u5E76%u8C03%u7528%60A%60%u7684%u62F7%u8D1D%u6784%u9020%u51FD%u6570%u3002%0A2.%20%u524D%u8005%u5728%u51FD%u6570%u4F53%u5185%uFF0C%u5BF9%60a%60%u7684%u4FEE%u6539%u4E0D%u4F1A%u5F71%u54CD%u5230%u5916%u90E8%60a%60%u5BF9%u8C61%u3002%u8FD9%u5F80%u5F80%u662F%u6211%u4EEC%u60F3%u8981%u7684%u3002%u6240%u4EE5%uFF0C%u6309%u5F15%u7528%u8C03%u7528%u7684%u65F6%u5019%uFF0C%u5F80%u5F80%u66F4%u597D%u7684%u5199%u6CD5%u662F%uFF1A%0A%60%60%60%0Avoid%20func%20%28const%20A%26%20a%29%3B%20//%20%u7528const%u6765%u4FDD%u8BC1a%u5BF9%u8C61%u4E0D%u88AB%u4FEE%u6539%0A%60%60%60%0A%0A%23%23%20%u4F5C%u4E3A%u8FD4%u56DE%u503C%0A%u5728%u5B9A%u4E49%u8FD0%u7B97%u7B26%u91CD%u8F7D%u7684%u65F6%u5019%uFF0C%u6211%u4EEC%u5F80%u5F80%u4F7F%u7528%60return%20*this%3B%60%u6765%u4FDD%u8BC1%u94FE%u5F0F%u8C03%u7528%uFF0C%u4F8B%u5982%uFF1A%0A%60%60%60%0Aclass%20A%20%7B%0A%09A%26%20operator%3D%28A%26%20param%29%7B%0A%09%09...%0A%09%09return%20*this%3B%0A%09%7D%3B%0A%7D%0AA%20a%2C%20b%2C%20c%3B%0Aa%20%3D%20b%20%3D%20c%3B%0A%60%60%60%0A%u5982%u679C%u4E0D%u6309%u5F15%u7528%u8FD4%u56DE%uFF0C%u53EF%u4EE5%u5417%uFF1F%0A%60%60%60%0Aclass%20A%20%7B%0A%09A%20operator%3D%28A%26%20param%29%7B%0A%09%09...%0A%09%09return%20*this%3B%0A%09%7D%3B%0A%7D%0AA%20a%2C%20b%2C%20c%3B%0Aa%20%3D%20b%20%3D%20c%3B%0A%60%60%60%0A%u7B54%u6848%u662F%u4E5F%u662F%u53EF%u4EE5%u7684%u3002%u533A%u522B%u662F%uFF1A%0A-%20%u4E0D%u6309%u5F15%u7528%u4F20%u9012%u65F6%uFF0C%60b%3Dc%60%u7684%u64CD%u4F5C%u8FD4%u56DE%u65F6%u4F1A%u5148%u5206%u914D%u4E00%u4E2A%u4E34%u65F6%u53D8%u91CF%uFF0C%u4EE5%60*this%60%u4E3A%u53C2%u6570%u8C03%u7528%60A%60%u7684%u62F7%u8D1D%u6784%u9020%u51FD%u6570%uFF0C%u7136%u540E%u518D%u8C03%u7528%u4E00%u6B21%60A%60%u7684%u62F7%u8D1D%u6784%u9020%u51FD%u6570%u5C06%u8BE5%u4E34%u65F6%u53D8%u91CF%u4F5C%u4E3A%u7ED3%u679C%u4F20%u9012%u7ED9%60a%60%u7684%60%3D%60%u64CD%u4F5C%u7B26%u51FD%u6570%u3002%0A-%20%u6309%u5F15%u7528%u4F20%u9012%uFF0C%u540C%u6837%60b%3Dc%60%u8FD4%u56DE%u65F6%u4F1A%u5206%u914D%u4E00%u4E2A%u4E34%u65F6%u53D8%u91CF%uFF0C%u5E76%u8C03%u7528%60A%60%u7684%u62F7%u8D1D%u6784%u9020%u51FD%u6570%uFF0C%u7136%u540E%u5C06%u8BE5%u4E34%u65F6%u53D8%u91CF%u7684%u5F15%u7528%u503C%u4F20%u7ED9%60a%60%u7684%60%3D%60%u64CD%u4F5C%u7B26%u51FD%u6570%u3002%0A%0A%u53EF%u89C1%u867D%u7136%u4E24%u8005%u90FD%u80FD%u505A%u5230%u94FE%u5F0F%u64CD%u4F5C%uFF0C%u4F46%u662F%u6309%u5F15%u7528%u8FD4%u56DE%u5C11%u8C03%u7528%u4E86%u4E00%u6B21%u62F7%u8D1D%u6784%u9020%u51FD%u6570%uFF0C%u6548%u7387%u63D0%u5347%u3002%u8FD9%u4E0E%u5F15%u7528%u5B58%u5728%u7684%u4EF7%u503C%u4E5F%u662F%u4E00%u81F4%u7684%u3002%0A%0A

Edit

这个知识点,在C++中看起来非常基本,但是初学者往往容易犯错。这里提及的是=的重载与拷贝构造函数。
当出现下面代码的时候,是调用=重载吗?

class A {}
A a;
A b = a;

答案是错,这里将会调用拷贝构造函数。如果没有显式定义拷贝构造函数,即调用默认拷贝构造函数,即浅拷贝,如果类定义中涉及内存的分配,则会出现意想不到的结果。
=运算符只会在赋值的时候使用,而在构造的时候会使用拷贝构造函数。如下是使用=的例子:

A a;
A b;
b = a;
%23%u8FD0%u7B97%u7B26%u91CD%u8F7D%u4E0E%u62F7%u8D1D%u6784%u9020%u51FD%u6570%0A@%28myblog%29%5Bc/c++%5D%0A%0A%u8FD9%u4E2A%u77E5%u8BC6%u70B9%uFF0C%u5728C++%u4E2D%u770B%u8D77%u6765%u975E%u5E38%u57FA%u672C%uFF0C%u4F46%u662F%u521D%u5B66%u8005%u5F80%u5F80%u5BB9%u6613%u72AF%u9519%u3002%u8FD9%u91CC%u63D0%u53CA%u7684%u662F%60%3D%60%u7684%u91CD%u8F7D%u4E0E%u62F7%u8D1D%u6784%u9020%u51FD%u6570%u3002%0A%u5F53%u51FA%u73B0%u4E0B%u9762%u4EE3%u7801%u7684%u65F6%u5019%uFF0C%u662F%u8C03%u7528%60%3D%60%u91CD%u8F7D%u5417%uFF1F%0A%60%60%60%0Aclass%20A%20%7B%7D%0AA%20a%3B%0AA%20b%20%3D%20a%3B%0A%60%60%60%0A%u7B54%u6848%u662F%u9519%uFF0C%u8FD9%u91CC%u5C06%u4F1A%u8C03%u7528%u62F7%u8D1D%u6784%u9020%u51FD%u6570%u3002%u5982%u679C%u6CA1%u6709%u663E%u5F0F%u5B9A%u4E49%u62F7%u8D1D%u6784%u9020%u51FD%u6570%uFF0C%u5373%u8C03%u7528%u9ED8%u8BA4%u62F7%u8D1D%u6784%u9020%u51FD%u6570%uFF0C%u5373%u6D45%u62F7%u8D1D%uFF0C%u5982%u679C%u7C7B%u5B9A%u4E49%u4E2D%u6D89%u53CA%u5185%u5B58%u7684%u5206%u914D%uFF0C%u5219%u4F1A%u51FA%u73B0%u610F%u60F3%u4E0D%u5230%u7684%u7ED3%u679C%u3002%0A%60%3D%60%u8FD0%u7B97%u7B26%u53EA%u4F1A%u5728%u8D4B%u503C%u7684%u65F6%u5019%u4F7F%u7528%uFF0C%u800C%u5728%u6784%u9020%u7684%u65F6%u5019%u4F1A%u4F7F%u7528%u62F7%u8D1D%u6784%u9020%u51FD%u6570%u3002%u5982%u4E0B%u662F%u4F7F%u7528%60%3D%60%u7684%u4F8B%u5B50%uFF1A%0A%60%60%60%0AA%20a%3B%0AA%20b%3B%0Ab%20%3D%20a%3B%0A%60%60%60

Edit


C++支持多继承,当父类继承自同一个超类,则即为本篇所述的菱形继承。类图如下:

主要参考两个链接:

前一篇提到的VS2003与后文中的实现方式相同,前一篇中还提到了Bjarne方案,不知哪些编译器采用这种方案。所以本文认为前者方案为主流方案,加以阐述。后者方案可视为前者方案的略微改良版。

单类虚继承

代码实现如下:

struct A {
virtual foo();
int X;
}
struct B : virtual public A {
virtual foo();
virtual fooB();
int Y;
}

其中VPTR指向Virtual Table (VTBL),VBPTR指向Virtual Base Table (VBTBL)。其内容为:

  1. 第一项为与本类VPTR的偏移。一般VPTR总是存在对象开始处。所以上例为-4字节,取补即为0xFFFFFFFC。如果本类没有虚函数,就没有VPTR,则该值为0。
  2. 从第二项开始为到各基类的偏移值,有几个基类,表项就有几个。上例中,只有一个基类,且本类成员变量会放在VBPTR之后,所以到基类A的偏移量即为8字节。

注意1: 只有出现了虚拟继承,才会有这样的内存布局,如果没有虚拟继承,则父类VPTR及其成员会挨着子类VPTR放置。
注意2: 此时VPTR中内容和无虚继承时的内容也不同。若B是普通继承A,则B类内存布局为:

菱形继承

对于这样一个菱形继承:

struct A
{
A(int v=100):X(v){};
virtual void foo(void){};
int X;
};
struct B :virtual public A
{
B(int v=10):Y(v),A(100){};
virtual void foo(void){};
virtual void fooB(void){}
int Y;
};
struct C : virtual public A
{
C(int v=20):Z(v),A(100){};
virtual void foo(void){};
virtual void fooC(void){};
int Z;
};
struct D : public B, public C
{
D(int v =40):B(10),C(20),A(100),L(v){};
virtual void foo(void){};
virtual void fooD(void){};
int L;
};

其主要特点为:

  • ABCD均包含虚函数,所以每个类都有虚函数表
  • 每个类均有成员变量
  • 父类BC对祖类采用虚继承
  • 子类对两个父类采用普通继承

这应当是最复杂的情况了,当有些类没有虚函数,或者没有成员变量时,情况可能稍许简单些。

A

A类因为没有虚拟继承,所以其内存布局为普通布局:

B / C

BC类均为单类虚继承,如上节所述:

D

D类最复杂

  1. 本类无覆盖关系的成员函数在最一开始的VPTR中,或认为在B::VPTR中
  2. 本类成员函数在所有直接父类对象的后面
  3. 只有一份A对象
  4. 本类如果覆盖任何父类或祖先类的成员函数会覆盖对应对象的VPTR中的项目。

Error: source type is not polymorphic

当祖先类A没有虚函数的时候,在发生向下转型(子类指针转成父类指针)的时候会出问题。可以查看Memory Layout for Multiple and Virtual Inheritance - Edsko de Vries, January 2006 中Downcasting一节。
考虑这样两个多继承的类:

Bottom* bottom1 = new Bottom();
AnotherBottom* bottom2 = new AnotherBottom();
Top* top1 = bottom1;
Top* top2 = bottom2;
Left* left = static_cast<Left*>(top1);

Bottom和AnotherBottom都继承自Left,Left虚继承自Top。现在要把一个Top指针转换成一个Left指针。使用static_cast会报error: cannot convert from base `Top’ to derived type `Left’ via virtual base `Top’。 因为需要运行时信息,因为所有的VPTR和对象内存布局,都是到运行时才建立的。于是想到可以用dynamic_cast

Left* left = dynamic_cast<Left*>(top1);

此时会报另一个错误:error: cannot dynamic_cast `top’ (of type `class Top*’) to type `class Left*’ (source type is not polymorphic)。这是因为Top类没有虚函数,所以此时Bottom和AnotherBottom对象的Top部分没有VPTR。于是编译器也分不清这是一个int还是一个对象。解决的方法就是为Top加一个虚函数。最方便的方法就是加一个空的虚析构函数,如下:

class Top {
virtual ~Top(){};
}

总结

当发生虚继承的时候,对象内部内存布局会产生大的变化,在引入VBPTR的同时,其各基类对象的排布顺序也发生了变化。

其他参考链接

%23%20C++%u83F1%u5F62%u7EE7%u627F%0A@%28myblog%29%5Bc/c++%5D%0AC++%u652F%u6301%u591A%u7EE7%u627F%uFF0C%u5F53%u7236%u7C7B%u7EE7%u627F%u81EA%u540C%u4E00%u4E2A%u8D85%u7C7B%uFF0C%u5219%u5373%u4E3A%u672C%u7BC7%u6240%u8FF0%u7684%u83F1%u5F62%u7EE7%u627F%u3002%u7C7B%u56FE%u5982%u4E0B%uFF1A%0A%21%5BAlt%20text%20%7C300x0%5D%28./1520316988125.png%29%0A%0A%u4E3B%u8981%u53C2%u8003%u4E24%u4E2A%u94FE%u63A5%uFF1A%0A-%20%5Bc++%u865A%u7EE7%u627F%u5BF9%u8C61%u7684%u5185%u5B58%u5E03%u5C40%5D%28http%3A//blog.csdn.net/BlueDog/article/details/4711169%29%0A-%20%5BMemory%20Layout%20for%20Multiple%20and%20Virtual%20Inheritance%20-%20Edsko%20de%20Vries%2C%20January%202006%5D%28https%3A//cs.nyu.edu/courses/fall16/CSCI-UA.0470-001/slides/MemoryLayoutMultipleInheritance.pdf%29%0A%0A%u524D%u4E00%u7BC7%u63D0%u5230%u7684VS2003%u4E0E%u540E%u6587%u4E2D%u7684%u5B9E%u73B0%u65B9%u5F0F%u76F8%u540C%uFF0C%u524D%u4E00%u7BC7%u4E2D%u8FD8%u63D0%u5230%u4E86Bjarne%u65B9%u6848%uFF0C%u4E0D%u77E5%u54EA%u4E9B%u7F16%u8BD1%u5668%u91C7%u7528%u8FD9%u79CD%u65B9%u6848%u3002%u6240%u4EE5%u672C%u6587%u8BA4%u4E3A%u524D%u8005%u65B9%u6848%u4E3A%u4E3B%u6D41%u65B9%u6848%uFF0C%u52A0%u4EE5%u9610%u8FF0%u3002%u540E%u8005%u65B9%u6848%u53EF%u89C6%u4E3A%u524D%u8005%u65B9%u6848%u7684%u7565%u5FAE%u6539%u826F%u7248%u3002%0A%0A%23%23%20%u5355%u7C7B%u865A%u7EE7%u627F%0A%u4EE3%u7801%u5B9E%u73B0%u5982%u4E0B%uFF1A%0A%60%60%60%0Astruct%20A%20%7B%0A%09virtual%20foo%28%29%3B%0A%09int%20X%3B%0A%7D%0Astruct%20B%20%3A%20virtual%20public%20A%20%7B%0A%09virtual%20foo%28%29%3B%0A%09virtual%20fooB%28%29%3B%0A%09int%20Y%3B%0A%7D%0A%60%60%60%0A%21%5BAlt%20text%5D%28./1520393159326.png%29%0A%0A%u5176%u4E2DVPTR%u6307%u5411Virtual%20Table%20%28VTBL%29%uFF0CVBPTR%u6307%u5411Virtual%20Base%20Table%20%28VBTBL%29%u3002%u5176%u5185%u5BB9%u4E3A%uFF1A%0A1.%20%u7B2C%u4E00%u9879%u4E3A%u4E0E%u672C%u7C7BVPTR%u7684%u504F%u79FB%u3002%u4E00%u822CVPTR%u603B%u662F%u5B58%u5728%u5BF9%u8C61%u5F00%u59CB%u5904%u3002%u6240%u4EE5%u4E0A%u4F8B%u4E3A-4%u5B57%u8282%uFF0C%u53D6%u8865%u5373%u4E3A0xFFFFFFFC%u3002%u5982%u679C%u672C%u7C7B%u6CA1%u6709%u865A%u51FD%u6570%uFF0C%u5C31%u6CA1%u6709VPTR%uFF0C%u5219%u8BE5%u503C%u4E3A0%u3002%0A2.%20%u4ECE%u7B2C%u4E8C%u9879%u5F00%u59CB%u4E3A%u5230%u5404%u57FA%u7C7B%u7684%u504F%u79FB%u503C%uFF0C%u6709%u51E0%u4E2A%u57FA%u7C7B%uFF0C%u8868%u9879%u5C31%u6709%u51E0%u4E2A%u3002%u4E0A%u4F8B%u4E2D%uFF0C%u53EA%u6709%u4E00%u4E2A%u57FA%u7C7B%uFF0C%u4E14%u672C%u7C7B%u6210%u5458%u53D8%u91CF%u4F1A%u653E%u5728VBPTR%u4E4B%u540E%uFF0C%u6240%u4EE5%u5230%u57FA%u7C7BA%u7684%u504F%u79FB%u91CF%u5373%u4E3A8%u5B57%u8282%u3002%0A%0A**%u6CE8%u610F1**%3A%20%u53EA%u6709%u51FA%u73B0%u4E86%u865A%u62DF%u7EE7%u627F%uFF0C%u624D%u4F1A%u6709%u8FD9%u6837%u7684%u5185%u5B58%u5E03%u5C40%uFF0C%u5982%u679C%u6CA1%u6709%u865A%u62DF%u7EE7%u627F%uFF0C%u5219%u7236%u7C7BVPTR%u53CA%u5176%u6210%u5458%u4F1A%u6328%u7740%u5B50%u7C7BVPTR%u653E%u7F6E%u3002%0A**%u6CE8%u610F2**%3A%20%u6B64%u65F6VPTR%u4E2D%u5185%u5BB9%u548C%u65E0%u865A%u7EE7%u627F%u65F6%u7684%u5185%u5BB9%u4E5F%u4E0D%u540C%u3002%u82E5B%u662F%u666E%u901A%u7EE7%u627FA%uFF0C%u5219B%u7C7B%u5185%u5B58%u5E03%u5C40%u4E3A%uFF1A%0A%21%5BAlt%20text%5D%28./1520393183452.png%29%0A%0A%23%23%20%u83F1%u5F62%u7EE7%u627F%0A%u5BF9%u4E8E%u8FD9%u6837%u4E00%u4E2A%u83F1%u5F62%u7EE7%u627F%uFF1A%0A%21%5BAlt%20text%5D%28./1520376926158.png%29%0A%u4EE3%u7801%u5B9E%u73B0%u5982%u4E0B%uFF1A%0A%60%60%60%0Astruct%20A%0A%7B%0A%20%20%20%20A%28int%20v%3D100%29%3AX%28v%29%7B%7D%3B%0A%20%20%20%20virtual%20void%20foo%28void%29%7B%7D%3B%0A%20%20%20%20int%20X%3B%0A%7D%3B%0Astruct%20B%20%3Avirtual%20public%20A%0A%7B%0A%20%20%20%20B%28int%20v%3D10%29%3AY%28v%29%2CA%28100%29%7B%7D%3B%0A%20%20%20%20virtual%20void%20foo%28void%29%7B%7D%3B%0A%20%20%20%20virtual%20void%20fooB%28void%29%7B%7D%0A%20%20%20%20int%20Y%3B%0A%7D%3B%0Astruct%20C%20%3A%20virtual%20public%20A%0A%7B%0A%20%20%20%20C%28int%20v%3D20%29%3AZ%28v%29%2CA%28100%29%7B%7D%3B%0A%20%20%20%20virtual%20void%20foo%28void%29%7B%7D%3B%0A%20%20%20%20virtual%20void%20fooC%28void%29%7B%7D%3B%0A%20%20%20%20int%20Z%3B%0A%7D%3B%0Astruct%20D%20%3A%20public%20B%2C%20public%20C%0A%7B%0A%20%20%20%20D%28int%20v%20%3D40%29%3AB%2810%29%2CC%2820%29%2CA%28100%29%2CL%28v%29%7B%7D%3B%0A%20%20%20%20virtual%20void%20foo%28void%29%7B%7D%3B%0A%20%20%20%20virtual%20void%20fooD%28void%29%7B%7D%3B%0A%20%20%20%20int%20L%3B%0A%7D%3B%0A%60%60%60%0A%u5176%u4E3B%u8981%u7279%u70B9%u4E3A%uFF1A%0A-%20ABCD%u5747%u5305%u542B%u865A%u51FD%u6570%uFF0C%u6240%u4EE5%u6BCF%u4E2A%u7C7B%u90FD%u6709%u865A%u51FD%u6570%u8868%0A-%20%u6BCF%u4E2A%u7C7B%u5747%u6709%u6210%u5458%u53D8%u91CF%0A-%20%u7236%u7C7BBC%u5BF9%u7956%u7C7B%u91C7%u7528%u865A%u7EE7%u627F%0A-%20%u5B50%u7C7B%u5BF9%u4E24%u4E2A%u7236%u7C7B%u91C7%u7528%u666E%u901A%u7EE7%u627F%0A%0A%u8FD9%u5E94%u5F53%u662F%u6700%u590D%u6742%u7684%u60C5%u51B5%u4E86%uFF0C%u5F53%u6709%u4E9B%u7C7B%u6CA1%u6709%u865A%u51FD%u6570%uFF0C%u6216%u8005%u6CA1%u6709%u6210%u5458%u53D8%u91CF%u65F6%uFF0C%u60C5%u51B5%u53EF%u80FD%u7A0D%u8BB8%u7B80%u5355%u4E9B%u3002%0A%23%23%23%20A%0AA%u7C7B%u56E0%u4E3A%u6CA1%u6709%u865A%u62DF%u7EE7%u627F%uFF0C%u6240%u4EE5%u5176%u5185%u5B58%u5E03%u5C40%u4E3A%u666E%u901A%u5E03%u5C40%uFF1A%0A%21%5BAlt%20text%5D%28./1520393228683.png%29%0A%0A%23%23%23%20B%20/%20C%0ABC%u7C7B%u5747%u4E3A%u5355%u7C7B%u865A%u7EE7%u627F%uFF0C%u5982%u4E0A%u8282%u6240%u8FF0%uFF1A%0A%21%5BAlt%20text%5D%28./1520393159326.png%29%0A%0A%23%23%23%20D%0AD%u7C7B%u6700%u590D%u6742%0A%21%5BAlt%20text%5D%28./1520393848842.png%29%0A%u9700%u8981%u6CE8%u610F%u7684%u662F%uFF1A%0A1.%20%u672C%u7C7B%u65E0%u8986%u76D6%u5173%u7CFB%u7684%u6210%u5458%u51FD%u6570%u5728%u6700%u4E00%u5F00%u59CB%u7684VPTR%u4E2D%uFF0C%u6216%u8BA4%u4E3A%u5728B%3A%3AVPTR%u4E2D%0A2.%20%u672C%u7C7B%u6210%u5458%u51FD%u6570%u5728%u6240%u6709%u76F4%u63A5%u7236%u7C7B%u5BF9%u8C61%u7684%u540E%u9762%0A3.%20%u53EA%u6709%u4E00%u4EFDA%u5BF9%u8C61%0A4.%20%u672C%u7C7B%u5982%u679C%u8986%u76D6%u4EFB%u4F55%u7236%u7C7B%u6216%u7956%u5148%u7C7B%u7684%u6210%u5458%u51FD%u6570%u4F1A%u8986%u76D6%u5BF9%u5E94%u5BF9%u8C61%u7684VPTR%u4E2D%u7684%u9879%u76EE%u3002%0A%0A%23%23%23%20Error%3A%20source%20type%20is%20not%20polymorphic%0A%u5F53%u7956%u5148%u7C7BA%u6CA1%u6709%u865A%u51FD%u6570%u7684%u65F6%u5019%uFF0C%u5728%u53D1%u751F%u5411%u4E0B%u8F6C%u578B%uFF08%u5B50%u7C7B%u6307%u9488%u8F6C%u6210%u7236%u7C7B%u6307%u9488%uFF09%u7684%u65F6%u5019%u4F1A%u51FA%u95EE%u9898%u3002%u53EF%u4EE5%u67E5%u770B%5BMemory%20Layout%20for%20Multiple%20and%20Virtual%20Inheritance%20-%20Edsko%20de%20Vries%2C%20January%202006%5D%28https%3A//cs.nyu.edu/courses/fall16/CSCI-UA.0470-001/slides/MemoryLayoutMultipleInheritance.pdf%29%20%u4E2DDowncasting%u4E00%u8282%u3002%0A%u8003%u8651%u8FD9%u6837%u4E24%u4E2A%u591A%u7EE7%u627F%u7684%u7C7B%uFF1A%0A%21%5BAlt%20text%5D%28./1520396776572.png%29%0A%60%60%60cpp%0ABottom*%20bottom1%20%3D%20new%20Bottom%28%29%3B%0AAnotherBottom*%20bottom2%20%3D%20new%20AnotherBottom%28%29%3B%0ATop*%20top1%20%3D%20bottom1%3B%0ATop*%20top2%20%3D%20bottom2%3B%0ALeft*%20left%20%3D%20static_cast%3CLeft*%3E%28top1%29%3B%0A%60%60%60%0ABottom%u548CAnotherBottom%u90FD%u7EE7%u627F%u81EALeft%uFF0CLeft%u865A%u7EE7%u627F%u81EATop%u3002%u73B0%u5728%u8981%u628A%u4E00%u4E2ATop%u6307%u9488%u8F6C%u6362%u6210%u4E00%u4E2ALeft%u6307%u9488%u3002%u4F7F%u7528%60static_cast%60%u4F1A%u62A5error%3A%20cannot%20convert%20from%20base%20%5C%60Top%27%20to%20derived%20type%20%5C%60Left%27%20via%20virtual%20base%20%5C%60Top%27%u3002%20%u56E0%u4E3A%u9700%u8981%u8FD0%u884C%u65F6%u4FE1%u606F%uFF0C%u56E0%u4E3A%u6240%u6709%u7684VPTR%u548C%u5BF9%u8C61%u5185%u5B58%u5E03%u5C40%uFF0C%u90FD%u662F%u5230%u8FD0%u884C%u65F6%u624D%u5EFA%u7ACB%u7684%u3002%u4E8E%u662F%u60F3%u5230%u53EF%u4EE5%u7528%60dynamic_cast%60%u3002%0A%60%60%60%0ALeft*%20left%20%3D%20dynamic_cast%3CLeft*%3E%28top1%29%3B%0A%60%60%60%0A%u6B64%u65F6%u4F1A%u62A5%u53E6%u4E00%u4E2A%u9519%u8BEF%uFF1Aerror%3A%20cannot%20dynamic_cast%20%5C%60top%27%20%28of%20type%20%5C%60class%20Top%5C*%27%29%20to%20type%20%5C%60class%20Left%5C*%27%20%28source%20type%20is%20not%20polymorphic%29%u3002%u8FD9%u662F%u56E0%u4E3ATop%u7C7B%u6CA1%u6709%u865A%u51FD%u6570%uFF0C%u6240%u4EE5%u6B64%u65F6Bottom%u548CAnotherBottom%u5BF9%u8C61%u7684Top%u90E8%u5206%u6CA1%u6709VPTR%u3002%u4E8E%u662F%u7F16%u8BD1%u5668%u4E5F%u5206%u4E0D%u6E05%u8FD9%u662F%u4E00%u4E2Aint%u8FD8%u662F%u4E00%u4E2A%u5BF9%u8C61%u3002%u89E3%u51B3%u7684%u65B9%u6CD5%u5C31%u662F%u4E3ATop%u52A0%u4E00%u4E2A%u865A%u51FD%u6570%u3002%u6700%u65B9%u4FBF%u7684%u65B9%u6CD5%u5C31%u662F%u52A0%u4E00%u4E2A%u7A7A%u7684%u865A%u6790%u6784%u51FD%u6570%uFF0C%u5982%u4E0B%uFF1A%0A%60%60%60%0Aclass%20Top%20%7B%0A%20virtual%20%7ETop%28%29%7B%7D%3B%0A%7D%0A%60%60%60%0A%0A%23%23%20%u603B%u7ED3%0A%u5F53%u53D1%u751F%u865A%u7EE7%u627F%u7684%u65F6%u5019%uFF0C%u5BF9%u8C61%u5185%u90E8%u5185%u5B58%u5E03%u5C40%u4F1A%u4EA7%u751F%u5927%u7684%u53D8%u5316%uFF0C%u5728%u5F15%u5165VBPTR%u7684%u540C%u65F6%uFF0C%u5176%u5404%u57FA%u7C7B%u5BF9%u8C61%u7684%u6392%u5E03%u987A%u5E8F%u4E5F%u53D1%u751F%u4E86%u53D8%u5316%u3002%0A%0A%23%23%20%u5176%u4ED6%u53C2%u8003%u94FE%u63A5%0A-%20%5B%u8BE6%u8C08C++%u865A%u51FD%u6570%u8868%u90A3%u56DE%u4E8B%uFF08%u591A%u91CD%u7EE7%u627F%u5173%u7CFB%2C%20%u65E0%u865A%u7EE7%u627F%uFF09%5D%28http%3A//blog.csdn.net/Li_Ning_/article/details/51893748%29%0A-%20%5B%u3010C++%u3011c++%u5355%u7EE7%u627F%u3001%u591A%u7EE7%u627F%u3001%u83F1%u5F62%u7EE7%u627F%u5185%u5B58%u5E03%u5C40%uFF08%u865A%u51FD%u6570%u8868%u7ED3%u6784%uFF09%5D%28http%3A//lib.csdn.net/article/cplusplus/51023%29%20%uFF08%u6B64%u7BC7%u5305%u542B%u4E86%u5BF9%u300Ac++%u865A%u7EE7%u627F%u5BF9%u8C61%u7684%u5185%u5B58%u5E03%u5C40%u300B%u4E00%u6587%u7684%u9610%u91CA%0A

Edit

最近做ThoughtWorks的面试题,第一遍用最简单的方法实现了,面试官说没有OO设计,于是乎想炫一波OO设计,结果才发现,原来C++还差的很远。先来说说这个多接口的坑。还会有另外的笔记阐述:

  • 运算符重载与拷贝构造函数
  • 菱形继承
  • 函数中的按引用调用与返回
  • 以后想到再加

C++中的接口

接口是面向对象很重要的概念。按照《敏捷软件开发-原则、模式与实践》一书所述,所有软件高层不应依赖于低层,而应依赖于抽象出的接口。这就是依赖倒置原则(DIP)。Java中的接口用interface定义,C++中没有提供专门的关键字。而是用纯虚函数来表示接口。形如:

class interface
{
public:
virtual void func() = 0;
}

接口是不能实例化的,因为包含了纯虚函数。

单类定义多接口

在Java中很容易做到,只需class A implement IA, IB{}即可。在C++中可否这么做呢?很容易就想到C++中的多继承,如下:

class IA {
public:
virtual void funcA() = 0;
}
class IB {
public:
virtual void funcB() = 0;
}
class C : public IA, public IB {
void funcA();
void funcB();
}

按照最初的设想,我希望能够:

C* c = new C();
IA* pA = (IA*)c;
IB* pB = (IB*)pA;
pA->funcA(); // 调用A函数
pB->funcB(); // 调用B函数

但我发现,现实与理想差得很远。pB->funcB()调用的其实也是funcA()。原因与多继承内存分布与类型转换有关。
在发生多继承时,一个C对象中内存分布如下,盗用陈浩的博客C++ 对象的内存布局中的图:

Base1* pA = (Base1*)derive;
Base2* pB = (Base2*)derive;

当发生向上类型转换时,编译器均能很好的工作,不用依赖于各种强制转换,也可以识别到正确的函数。但是如果发生非正常的类型转换时,就会遇到问题。例如前文所述的将Base1型指针直接转型到Base2就会出问题。可参考这一篇博文:当C++多继承遇上类型转换。文中提到了三个解决方案,我尝试了前两个,分别用static_castdynamic_cast均不能解决。奇怪的是,dynamic_cast的解决方案看起来在网上确是颇有一些支持者,看下面的链接:

在我自己的code中,dynamic_cast之后的结果是虽然没有抛出bad cast异常,但是转换的结构是NULL。

解决方案

上面提到的方案,都不成功,但最终我还是找到了能解决的办法,尽管看起来不像想象中优雅。

方案一:采用菱形继承

根据查阅的各种网站资料,这样的继承会增加内存布局,以及调用的复杂度。但确实能解决上面多接口转型的问题。具体代码如下:

class IBase
class IA : virtual public IBase {}
class IB : virtual public IBase {}
class C : public IA, public IB {}
IA* pA = new C();
IBase* base = (IBase*)pA;
IB* pB = dynamic_cast<IB*>(base);

这样的做法,让人如鲠在喉,一个简单的调用,搞的这么复杂。转来转去,可读性极差,而且dynamic_cast还有性能问题。
而且这里还会遇到source type is not polymorphic的问题,解决方法使添加虚析构函数。

class IBase {
virtual ~IBase(){};
}
class IA : virtual public IBase {}
class IB : virtual public IBase {}
class C : public IA, public IB {}
IA* pA = new C();
IBase* base = (IBase*)pA;
IB* pB = dynamic_cast<IB*>(base);

方案二:采用单接口

这一方案,是受了下面的链接的启发:Implementing multiple interfaces in a single C++ class

As you found out, you cannot implement two interfaces with one single C++ class directly. However, you could simply define a new Slice interface derived from the two other Slice interfaces, and then implement this new Slice interface with a single C++ class.

作者说C++中直接定义多接口并不是一个好的实现,定义一个虚接口类来继承两个虚接口,实现类直接继承自这个虚类。代码如下:

class IA {}
class IB {}
class IAB : public IA, public IB {}
class C : public IAB {}

这样转型起来就方便多了

C* c = new C();
IA* pA = (IA*)c;
IB* pB = (IB*)pA; // 仍会出错,不能直接转
IB* pB2 = (IB*)(IAB*)pA; // 可以工作

但其实上层的代码,应该依赖于IAB,而不应该也不能够只依赖于IA, IB,而对IAB一无所知。

总结

  1. 在设计接口的时候,不要指望用多继承来模仿Java里的多接口定义。
  2. 尽量避免在多继承的时候,需要在没有继承关系(IA & IB)之间进行指针转型。虽然菱形继承+dynamic_cast可以做到,但是可读性和性能会下降。
  3. 可以用方案二中的方法来实现近似的多接口定义。这是一个相对简介有效的方法。
%23%20C++%u5355%u7C7B%u5B9A%u4E49%u591A%u63A5%u53E3%0A@%28myblog%29%5Bc/c++%5D%0A%0A%u6700%u8FD1%u505AThoughtWorks%u7684%u9762%u8BD5%u9898%uFF0C%u7B2C%u4E00%u904D%u7528%u6700%u7B80%u5355%u7684%u65B9%u6CD5%u5B9E%u73B0%u4E86%uFF0C%u9762%u8BD5%u5B98%u8BF4%u6CA1%u6709OO%u8BBE%u8BA1%uFF0C%u4E8E%u662F%u4E4E%u60F3%u70AB%u4E00%u6CE2OO%u8BBE%u8BA1%uFF0C%u7ED3%u679C%u624D%u53D1%u73B0%uFF0C%u539F%u6765C++%u8FD8%u5DEE%u7684%u5F88%u8FDC%u3002%u5148%u6765%u8BF4%u8BF4%u8FD9%u4E2A%u591A%u63A5%u53E3%u7684%u5751%u3002%u8FD8%u4F1A%u6709%u53E6%u5916%u7684%u7B14%u8BB0%u9610%u8FF0%uFF1A%0A-%20%u8FD0%u7B97%u7B26%u91CD%u8F7D%u4E0E%u62F7%u8D1D%u6784%u9020%u51FD%u6570%0A-%20%u83F1%u5F62%u7EE7%u627F%0A-%20%u51FD%u6570%u4E2D%u7684%u6309%u5F15%u7528%u8C03%u7528%u4E0E%u8FD4%u56DE%0A-%20%u4EE5%u540E%u60F3%u5230%u518D%u52A0%0A%0A%23%23%20C++%u4E2D%u7684%u63A5%u53E3%0A%u63A5%u53E3%u662F%u9762%u5411%u5BF9%u8C61%u5F88%u91CD%u8981%u7684%u6982%u5FF5%u3002%u6309%u7167%u300A%u654F%u6377%u8F6F%u4EF6%u5F00%u53D1-%u539F%u5219%u3001%u6A21%u5F0F%u4E0E%u5B9E%u8DF5%u300B%u4E00%u4E66%u6240%u8FF0%uFF0C%u6240%u6709%u8F6F%u4EF6%u9AD8%u5C42%u4E0D%u5E94%u4F9D%u8D56%u4E8E%u4F4E%u5C42%uFF0C%u800C%u5E94%u4F9D%u8D56%u4E8E%u62BD%u8C61%u51FA%u7684%u63A5%u53E3%u3002%u8FD9%u5C31%u662F%u4F9D%u8D56%u5012%u7F6E%u539F%u5219%28DIP%29%u3002Java%u4E2D%u7684%u63A5%u53E3%u7528%60interface%60%u5B9A%u4E49%uFF0CC++%u4E2D%u6CA1%u6709%u63D0%u4F9B%u4E13%u95E8%u7684%u5173%u952E%u5B57%u3002%u800C%u662F%u7528%u7EAF%u865A%u51FD%u6570%u6765%u8868%u793A%u63A5%u53E3%u3002%u5F62%u5982%uFF1A%0A%60%60%60%0Aclass%20interface%0A%7B%0Apublic%3A%0A%09virtual%20void%20func%28%29%20%3D%200%3B%0A%7D%0A%60%60%60%0A%u63A5%u53E3%u662F%u4E0D%u80FD%u5B9E%u4F8B%u5316%u7684%uFF0C%u56E0%u4E3A%u5305%u542B%u4E86%u7EAF%u865A%u51FD%u6570%u3002%0A%0A%23%23%u5355%u7C7B%u5B9A%u4E49%u591A%u63A5%u53E3%0A%u5728Java%u4E2D%u5F88%u5BB9%u6613%u505A%u5230%uFF0C%u53EA%u9700%60class%20A%20implement%20IA%2C%20IB%7B%7D%60%u5373%u53EF%u3002%u5728C++%u4E2D%u53EF%u5426%u8FD9%u4E48%u505A%u5462%uFF1F%u5F88%u5BB9%u6613%u5C31%u60F3%u5230C++%u4E2D%u7684%u591A%u7EE7%u627F%uFF0C%u5982%u4E0B%uFF1A%0A%60%60%60%0Aclass%20IA%20%7B%0Apublic%3A%0A%09virtual%20void%20funcA%28%29%20%3D%200%3B%0A%7D%0Aclass%20IB%20%7B%0Apublic%3A%0A%09virtual%20void%20funcB%28%29%20%3D%200%3B%0A%7D%0Aclass%20C%20%3A%20public%20IA%2C%20public%20IB%20%7B%0A%09void%20funcA%28%29%3B%0A%09void%20funcB%28%29%3B%0A%7D%0A%60%60%60%0A%u6309%u7167%u6700%u521D%u7684%u8BBE%u60F3%uFF0C%u6211%u5E0C%u671B%u80FD%u591F%uFF1A%0A%60%60%60%0AC*%20c%20%3D%20new%20C%28%29%3B%0AIA*%20pA%20%3D%20%28IA*%29c%3B%0AIB*%20pB%20%3D%20%28IB*%29pA%3B%0ApA-%3EfuncA%28%29%3B%20//%20%u8C03%u7528A%u51FD%u6570%0ApB-%3EfuncB%28%29%3B%20//%20%u8C03%u7528B%u51FD%u6570%0A%60%60%60%0A%u4F46%u6211%u53D1%u73B0%uFF0C%u73B0%u5B9E%u4E0E%u7406%u60F3%u5DEE%u5F97%u5F88%u8FDC%u3002%60pB-%3EfuncB%28%29%60%u8C03%u7528%u7684%u5176%u5B9E%u4E5F%u662F%60funcA%28%29%60%u3002%u539F%u56E0%u4E0E%u591A%u7EE7%u627F%u5185%u5B58%u5206%u5E03%u4E0E%u7C7B%u578B%u8F6C%u6362%u6709%u5173%u3002%0A%u5728%u53D1%u751F%u591A%u7EE7%u627F%u65F6%uFF0C%u4E00%u4E2AC%u5BF9%u8C61%u4E2D%u5185%u5B58%u5206%u5E03%u5982%u4E0B%uFF0C%u76D7%u7528%u9648%u6D69%u7684%u535A%u5BA2%5BC++%20%u5BF9%u8C61%u7684%u5185%u5B58%u5E03%u5C40%5D%28http%3A//blog.csdn.net/haoel/article/details/3081328%29%u4E2D%u7684%u56FE%uFF1A%0A%21%5BAlt%20text%5D%28./1520307655931.png%29%20%21%5BAlt%20text%5D%28./1520307665220.png%29%0A%0A%60%60%60%0ABase1*%20pA%20%3D%20%28Base1*%29derive%3B%0ABase2*%20pB%20%3D%20%28Base2*%29derive%3B%0A%60%60%60%0A%u5F53%u53D1%u751F%u5411%u4E0A%u7C7B%u578B%u8F6C%u6362%u65F6%uFF0C%u7F16%u8BD1%u5668%u5747%u80FD%u5F88%u597D%u7684%u5DE5%u4F5C%uFF0C%u4E0D%u7528%u4F9D%u8D56%u4E8E%u5404%u79CD%u5F3A%u5236%u8F6C%u6362%uFF0C%u4E5F%u53EF%u4EE5%u8BC6%u522B%u5230%u6B63%u786E%u7684%u51FD%u6570%u3002%u4F46%u662F%u5982%u679C%u53D1%u751F%u975E%u6B63%u5E38%u7684%u7C7B%u578B%u8F6C%u6362%u65F6%uFF0C%u5C31%u4F1A%u9047%u5230%u95EE%u9898%u3002%u4F8B%u5982%u524D%u6587%u6240%u8FF0%u7684%u5C06%60Base1%60%u578B%u6307%u9488%u76F4%u63A5%u8F6C%u578B%u5230%60Base2%60%u5C31%u4F1A%u51FA%u95EE%u9898%u3002%u53EF%u53C2%u8003%u8FD9%u4E00%u7BC7%u535A%u6587%uFF1A%5B%u5F53C++%u591A%u7EE7%u627F%u9047%u4E0A%u7C7B%u578B%u8F6C%u6362%5D%28http%3A//blog.csdn.net/smstong/article/details/24455371%29%u3002%u6587%u4E2D%u63D0%u5230%u4E86%u4E09%u4E2A%u89E3%u51B3%u65B9%u6848%uFF0C%u6211%u5C1D%u8BD5%u4E86%u524D%u4E24%u4E2A%uFF0C%u5206%u522B%u7528%60static_cast%60%u548C%60dynamic_cast%60%u5747%u4E0D%u80FD%u89E3%u51B3%u3002%u5947%u602A%u7684%u662F%uFF0C%60dynamic_cast%60%u7684%u89E3%u51B3%u65B9%u6848%u770B%u8D77%u6765%u5728%u7F51%u4E0A%u786E%u662F%u9887%u6709%u4E00%u4E9B%u652F%u6301%u8005%uFF0C%u770B%u4E0B%u9762%u7684%u94FE%u63A5%uFF1A%0A-%20%5BMultiple%20inheritance%20casting%20from%20base%20class%20to%20a%20different%20derived%20class%0A%5D%28https%3A//stackoverflow.com/questions/15242841/multiple-inheritance-casting-from-base-class-to-a-different-derived-class%29%0A-%20%5BType%20casting%20to%20an%20interface%20%28Abstract%20class%29%20in%20case%20of%20Multiple%20Inheritance%20in%20C++%0A%5D%28https%3A//stackoverflow.com/questions/14121297/type-casting-to-an-interface-abstract-class-in-case-of-multiple-inheritance-in%29%0A-%20%5BHow%20to%20perform%20casting%20with%20multiple%20inheritance%0A%5D%28https%3A//stackoverflow.com/questions/5715865/how-to-perform-casting-with-multiple-inheritance%29%0A%0A%u5728%u6211%u81EA%u5DF1%u7684code%u4E2D%uFF0C%60dynamic_cast%60%u4E4B%u540E%u7684%u7ED3%u679C%u662F%u867D%u7136%u6CA1%u6709%u629B%u51FAbad%20cast%u5F02%u5E38%uFF0C%u4F46%u662F%u8F6C%u6362%u7684%u7ED3%u6784%u662FNULL%u3002%0A%0A%23%23%20%u89E3%u51B3%u65B9%u6848%0A%u4E0A%u9762%u63D0%u5230%u7684%u65B9%u6848%uFF0C%u90FD%u4E0D%u6210%u529F%uFF0C%u4F46%u6700%u7EC8%u6211%u8FD8%u662F%u627E%u5230%u4E86%u80FD%u89E3%u51B3%u7684%u529E%u6CD5%uFF0C%u5C3D%u7BA1%u770B%u8D77%u6765%u4E0D%u50CF%u60F3%u8C61%u4E2D%u4F18%u96C5%u3002%0A%23%23%23%20%u65B9%u6848%u4E00%uFF1A%u91C7%u7528%u83F1%u5F62%u7EE7%u627F%0A%u6839%u636E%u67E5%u9605%u7684%u5404%u79CD%u7F51%u7AD9%u8D44%u6599%uFF0C%u8FD9%u6837%u7684%u7EE7%u627F%u4F1A%u589E%u52A0%u5185%u5B58%u5E03%u5C40%uFF0C%u4EE5%u53CA%u8C03%u7528%u7684%u590D%u6742%u5EA6%u3002%u4F46%u786E%u5B9E%u80FD%u89E3%u51B3%u4E0A%u9762%u591A%u63A5%u53E3%u8F6C%u578B%u7684%u95EE%u9898%u3002%u5177%u4F53%u4EE3%u7801%u5982%u4E0B%uFF1A%0A%60%60%60%0Aclass%20IBase%0Aclass%20IA%20%3A%20virtual%20public%20IBase%20%7B%7D%0Aclass%20IB%20%3A%20virtual%20public%20IBase%20%7B%7D%0Aclass%20C%20%3A%20public%20IA%2C%20public%20IB%20%7B%7D%0A%0AIA*%20pA%20%3D%20new%20C%28%29%3B%0AIBase*%20base%20%3D%20%28IBase*%29pA%3B%0AIB*%20pB%20%3D%20dynamic_cast%3CIB*%3E%28base%29%3B%0A%60%60%60%20%0A%u8FD9%u6837%u7684%u505A%u6CD5%uFF0C%u8BA9%u4EBA%u5982%u9CA0%u5728%u5589%uFF0C%u4E00%u4E2A%u7B80%u5355%u7684%u8C03%u7528%uFF0C%u641E%u7684%u8FD9%u4E48%u590D%u6742%u3002%u8F6C%u6765%u8F6C%u53BB%uFF0C%u53EF%u8BFB%u6027%u6781%u5DEE%uFF0C%u800C%u4E14%60dynamic_cast%60%u8FD8%u6709%u6027%u80FD%u95EE%u9898%u3002%0A%u800C%u4E14%u8FD9%u91CC%u8FD8%u4F1A%u9047%u5230source%20type%20is%20not%20polymorphic%u7684%u95EE%u9898%uFF0C%u89E3%u51B3%u65B9%u6CD5%u4F7F%u6DFB%u52A0%u865A%u6790%u6784%u51FD%u6570%u3002%0A%60%60%60%0Aclass%20IBase%20%7B%0A%09virtual%20%7EIBase%28%29%7B%7D%3B%0A%7D%0Aclass%20IA%20%3A%20virtual%20public%20IBase%20%7B%7D%20%0Aclass%20IB%20%3A%20virtual%20public%20IBase%20%7B%7D%0Aclass%20C%20%3A%20public%20IA%2C%20public%20IB%20%7B%7D%0A%0AIA*%20pA%20%3D%20new%20C%28%29%3B%0AIBase*%20base%20%3D%20%28IBase*%29pA%3B%0AIB*%20pB%20%3D%20dynamic_cast%3CIB*%3E%28base%29%3B%0A%60%60%60%20%0A%0A%23%23%23%20%u65B9%u6848%u4E8C%uFF1A%u91C7%u7528%u5355%u63A5%u53E3%0A%u8FD9%u4E00%u65B9%u6848%uFF0C%u662F%u53D7%u4E86%u4E0B%u9762%u7684%u94FE%u63A5%u7684%u542F%u53D1%uFF1A%5BImplementing%20multiple%20interfaces%20in%20a%20single%20C++%20class%5D%28https%3A//forums.zeroc.com/discussion/4994/implementing-multiple-interfaces-in-a-single-c-class%29%0A%0A%3E%20As%20you%20found%20out%2C%20**you%20cannot%20implement%20two%20interfaces%20with%20one%20single%20C++%20class%20directly**.%20However%2C%20you%20could%20simply%20define%20a%20new%20Slice%20interface%20derived%20from%20the%20two%20other%20Slice%20interfaces%2C%20and%20then%20implement%20this%20new%20Slice%20interface%20with%20a%20single%20C++%20class.%0A%0A%u4F5C%u8005%u8BF4C++%u4E2D%u76F4%u63A5%u5B9A%u4E49%u591A%u63A5%u53E3%u5E76%u4E0D%u662F%u4E00%u4E2A%u597D%u7684%u5B9E%u73B0%uFF0C%u5B9A%u4E49%u4E00%u4E2A%u865A%u63A5%u53E3%u7C7B%u6765%u7EE7%u627F%u4E24%u4E2A%u865A%u63A5%u53E3%uFF0C%u5B9E%u73B0%u7C7B%u76F4%u63A5%u7EE7%u627F%u81EA%u8FD9%u4E2A%u865A%u7C7B%u3002%u4EE3%u7801%u5982%u4E0B%3A%0A%60%60%60%0Aclass%20IA%20%7B%7D%0Aclass%20IB%20%7B%7D%0Aclass%20IAB%20%3A%20public%20IA%2C%20public%20IB%20%7B%7D%0Aclass%20C%20%3A%20public%20IAB%20%7B%7D%0A%60%60%60%0A%u8FD9%u6837%u8F6C%u578B%u8D77%u6765%u5C31%u65B9%u4FBF%u591A%u4E86%0A%60%60%60%0AC*%20c%20%3D%20new%20C%28%29%3B%0AIA*%20pA%20%3D%20%28IA*%29c%3B%0AIB*%20pB%20%3D%20%28IB*%29pA%3B%20//%20%u4ECD%u4F1A%u51FA%u9519%uFF0C%u4E0D%u80FD%u76F4%u63A5%u8F6C%0AIB*%20pB2%20%3D%20%28IB*%29%28IAB*%29pA%3B%20//%20%u53EF%u4EE5%u5DE5%u4F5C%0A%60%60%60%0A%u4F46%u5176%u5B9E%u4E0A%u5C42%u7684%u4EE3%u7801%uFF0C%u5E94%u8BE5%u4F9D%u8D56%u4E8E%60IAB%60%uFF0C%u800C%u4E0D%u5E94%u8BE5%u4E5F%u4E0D%u80FD%u591F%u53EA%u4F9D%u8D56%u4E8E%60IA%60%2C%20%60IB%60%uFF0C%u800C%u5BF9%60IAB%60%u4E00%u65E0%u6240%u77E5%u3002%0A%0A%23%23%20%u603B%u7ED3%0A1.%20%u5728%u8BBE%u8BA1%u63A5%u53E3%u7684%u65F6%u5019%uFF0C%u4E0D%u8981%u6307%u671B%u7528%u591A%u7EE7%u627F%u6765%u6A21%u4EFFJava%u91CC%u7684%u591A%u63A5%u53E3%u5B9A%u4E49%u3002%0A2.%20%u5C3D%u91CF%u907F%u514D%u5728%u591A%u7EE7%u627F%u7684%u65F6%u5019%uFF0C%u9700%u8981%u5728%u6CA1%u6709%u7EE7%u627F%u5173%u7CFB%28%60IA%60%20%26%20%60IB%60%29%u4E4B%u95F4%u8FDB%u884C%u6307%u9488%u8F6C%u578B%u3002%u867D%u7136%u83F1%u5F62%u7EE7%u627F+%60dynamic_cast%60%u53EF%u4EE5%u505A%u5230%uFF0C%u4F46%u662F%u53EF%u8BFB%u6027%u548C%u6027%u80FD%u4F1A%u4E0B%u964D%u3002%0A3.%20%u53EF%u4EE5%u7528%u65B9%u6848%u4E8C%u4E2D%u7684%u65B9%u6CD5%u6765%u5B9E%u73B0%u8FD1%u4F3C%u7684%u591A%u63A5%u53E3%u5B9A%u4E49%u3002%u8FD9%u662F%u4E00%u4E2A%u76F8%u5BF9%u7B80%u4ECB%u6709%u6548%u7684%u65B9%u6CD5%u3002%0A

Edit

最近在维护一个Xposed模块[]Niwatori-One Handed Mode](https://github.com/tkgktyk/Niwatori)。原作者tkgktyk已经停止更新了,导致模块在Xposed Framework for Nougat发布以后,不能使用。于是我fork了一份代码,开始做Android Nougat上的适配工作,并在XDA上发布了更新链接
在适配了Nougat之后,希望能添加一些新功能,让用户体验更好。目前想做的是能通过fooview调用Niwatori的快捷方式。并且该快捷方式的功能,例如是small screen还是slide down等等,能通过Niwatori本身进行配置。但是在开发这一功能的时候,发现动态快捷方式的加载需要使用SDK 25以上版本,而从SDK 25开始,原先SharedPreference的打开方式MODE_WORLD_PRIVATE已经被禁止了。使用它会导致security exception。
所以要升到使用SDK 25,必须解决preference引用的问题。那么这个模式的变化,到底会在哪里影响到我们的Xposed模块呢?

Xposed中的preference

Xposed模块中使用preference的时候,通常都是通过XSharedPreference来操作。XSharedPreference在Android标准的SharedPreference类上包了一层,提供了一些security的fix或者work around。例如:XSharedPreference.makeWorldReadable。他们都是加载app data文件夹下的xml文件来读取、存储键值对的。该文件路径为(以Niwatori为例):/data/data/jp.tkgktyk.xposed.niwatori/shared_prefs/jp.tkgktyk.xposed.niwatori_preferences.xml

通常Xposed中如下使用preference会按照如下的时序图,以Niwatori为例:

  • XSharedPreference实例创建在模块加载的initZygote
  • 数据的使用通过钩子函数,在各个app的Context底下执行

于是当MODE_WORLD_READABLE被废止以后,这里就出问题了。即在默认情况下,app1是没有权限查看Niwatori的preference文件的,也就没法加载配置数据。

Xposed官方或者作者rovo89还没有给出官方的解决办法,但总是会有一些未雨绸缪的勇士,XDA上有一个帖子给出了一个work around:MODE_WORLD_READABLE in Android N

我在Niwatori中也使用了该方法,但仍然不是完美解决,而且目前还不知道如何改进。

遗留的问题

该work around和XSharedPreference.makeWorldReadable同理,我如下调用preference:

mPrefs.makeWorldReadable();
Log.e("Ben", "package:" + decorView.getContext().getPackageName() + ", " + decorView + "," + mPrefs.getString("key_boundary_color_ms", "default value"));
Log.e("Ben", "file can read: " + mPrefs.getFile().canRead()); <-- 有些app会是true,有些app会是false

当返回true的时候,settings就成功的传到了对应app了。这个时而可以read时而不可以read,我也很苦恼,不知道是怎么回事儿。留待以后再解决了。

解决遗留的问题 - 20180119

以上的问题在于,Android 7.0开始,即从SDK 24开始,Android加入了很多security方面的特性,参考Android 7.0 Security Features: Direct Boot。这和我们的问题不太相关。相关的是如上所说,Nougat不允许world readable的文件了。如果用SDK25编译的app还用MODE_WORLD_READABLE,系统会报exception。
Google上鲜少有相关的解决方案,有如下几个链接可以参考:

经过验证,是XposedBridge issue 1中GravityBox作者的一个comment提到了最终的解决方法。该comment如下:

  • setStorageDeviceProtected
  • createDeviceProtectedStorageContext

将preference文件存到/data/user_de/0/<package name>/shared_prefs下。并在Xposed的context端,直接打开文件进行操作。
但其实我们并不需如此。只要保证package folder的权限至少是711,preference.xml文件有可读权限即可。

%23%20XSharedPreference%20%26%20SharedPreference%20-%20XPosed%u6A21%u5757%u4E2D%u7684preference%u4F7F%u7528%0A@%28myblog%29%5BAndroid%2C%20xposed%5D%0A%0A%u6700%u8FD1%u5728%u7EF4%u62A4%u4E00%u4E2AXposed%u6A21%u5757%5B%5DNiwatori-One%20Handed%20Mode%5D%28https%3A//github.com/tkgktyk/Niwatori%29%u3002%u539F%u4F5C%u8005tkgktyk%u5DF2%u7ECF%u505C%u6B62%u66F4%u65B0%u4E86%uFF0C%u5BFC%u81F4%u6A21%u5757%u5728Xposed%20Framework%20for%20Nougat%u53D1%u5E03%u4EE5%u540E%uFF0C%u4E0D%u80FD%u4F7F%u7528%u3002%u4E8E%u662F%u6211fork%u4E86%u4E00%u4EFD%u4EE3%u7801%uFF0C%u5F00%u59CB%u505AAndroid%20Nougat%u4E0A%u7684%u9002%u914D%u5DE5%u4F5C%uFF0C%u5E76%u5728XDA%u4E0A%u53D1%u5E03%u4E86%u66F4%u65B0%5B%u94FE%u63A5%5D%28https%3A//forum.xda-developers.com/xposed/modules/mod-niwatori-one-handed-mode-t3730963%29%u3002%0A%u5728%u9002%u914D%u4E86Nougat%u4E4B%u540E%uFF0C%u5E0C%u671B%u80FD%u6DFB%u52A0%u4E00%u4E9B%u65B0%u529F%u80FD%uFF0C%u8BA9%u7528%u6237%u4F53%u9A8C%u66F4%u597D%u3002%u76EE%u524D%u60F3%u505A%u7684%u662F%u80FD%u901A%u8FC7fooview%u8C03%u7528Niwatori%u7684%u5FEB%u6377%u65B9%u5F0F%u3002%u5E76%u4E14%u8BE5%u5FEB%u6377%u65B9%u5F0F%u7684%u529F%u80FD%uFF0C%u4F8B%u5982%u662Fsmall%20screen%u8FD8%u662Fslide%20down%u7B49%u7B49%uFF0C%u80FD%u901A%u8FC7Niwatori%u672C%u8EAB%u8FDB%u884C%u914D%u7F6E%u3002%u4F46%u662F%u5728%u5F00%u53D1%u8FD9%u4E00%u529F%u80FD%u7684%u65F6%u5019%uFF0C%u53D1%u73B0%u52A8%u6001%u5FEB%u6377%u65B9%u5F0F%u7684%u52A0%u8F7D%u9700%u8981%u4F7F%u7528SDK%2025%u4EE5%u4E0A%u7248%u672C%uFF0C%u800C%u4ECESDK%2025%u5F00%u59CB%uFF0C%u539F%u5148SharedPreference%u7684%u6253%u5F00%u65B9%u5F0FMODE%5C_WORLD%5C_PRIVATE%u5DF2%u7ECF%u88AB%u7981%u6B62%u4E86%u3002%u4F7F%u7528%u5B83%u4F1A%u5BFC%u81F4security%20exception%u3002%0A%u6240%u4EE5%u8981%u5347%u5230%u4F7F%u7528SDK%2025%uFF0C%u5FC5%u987B%u89E3%u51B3preference%u5F15%u7528%u7684%u95EE%u9898%u3002%u90A3%u4E48%u8FD9%u4E2A%u6A21%u5F0F%u7684%u53D8%u5316%uFF0C%u5230%u5E95%u4F1A%u5728%u54EA%u91CC%u5F71%u54CD%u5230%u6211%u4EEC%u7684Xposed%u6A21%u5757%u5462%uFF1F%0A%0A%23%23%20Xposed%u4E2D%u7684preference%0AXposed%u6A21%u5757%u4E2D%u4F7F%u7528preference%u7684%u65F6%u5019%uFF0C%u901A%u5E38%u90FD%u662F%u901A%u8FC7XSharedPreference%u6765%u64CD%u4F5C%u3002XSharedPreference%u5728Android%u6807%u51C6%u7684SharedPreference%u7C7B%u4E0A%u5305%u4E86%u4E00%u5C42%uFF0C%u63D0%u4F9B%u4E86%u4E00%u4E9Bsecurity%u7684fix%u6216%u8005work%20around%u3002%u4F8B%u5982%uFF1AXSharedPreference.makeWorldReadable%u3002%u4ED6%u4EEC%u90FD%u662F%u52A0%u8F7Dapp%20data%u6587%u4EF6%u5939%u4E0B%u7684xml%u6587%u4EF6%u6765%u8BFB%u53D6%u3001%u5B58%u50A8%u952E%u503C%u5BF9%u7684%u3002%u8BE5%u6587%u4EF6%u8DEF%u5F84%u4E3A%uFF08%u4EE5Niwatori%u4E3A%u4F8B%uFF09%uFF1A%60/data/data/jp.tkgktyk.xposed.niwatori/shared_prefs/jp.tkgktyk.xposed.niwatori_preferences.xml%60%u3002%0A%0A%u901A%u5E38Xposed%u4E2D%u5982%u4E0B%u4F7F%u7528preference%u4F1A%u6309%u7167%u5982%u4E0B%u7684%u65F6%u5E8F%u56FE%uFF0C%u4EE5Niwatori%u4E3A%u4F8B%uFF1A%0A%60%60%60%20sequence%0ANote%20left%20of%20Niwatori%3A%20initZygote%0ANote%20left%20of%20Niwatori%3A%20Construct%20a%20XSharedPreference%0ANiwatori-%3EActivity.class%3A%20hook%0AActivity.class-%3Eapp1%3A%20onCreate%0ANote%20right%20of%20app1%3A%20load%20the%20XSharedPreference%0AActivity.class-%3Eapp2%3A%20onCreate%0ANote%20right%20of%20app2%3A%20load%20the%20XSharedPreference%0A%60%60%60%0A-%20XSharedPreference%u5B9E%u4F8B%u521B%u5EFA%u5728%u6A21%u5757%u52A0%u8F7D%u7684%60initZygote%60%u4E2D%0A-%20%u6570%u636E%u7684%u4F7F%u7528%u901A%u8FC7%u94A9%u5B50%u51FD%u6570%uFF0C%u5728%u5404%u4E2Aapp%u7684Context%u5E95%u4E0B%u6267%u884C%0A%0A%u4E8E%u662F%u5F53MODE%5C_WORLD%5C_READABLE%u88AB%u5E9F%u6B62%u4EE5%u540E%uFF0C%u8FD9%u91CC%u5C31%u51FA%u95EE%u9898%u4E86%u3002%u5373%u5728%u9ED8%u8BA4%u60C5%u51B5%u4E0B%uFF0Capp1%u662F%u6CA1%u6709%u6743%u9650%u67E5%u770BNiwatori%u7684preference%u6587%u4EF6%u7684%uFF0C%u4E5F%u5C31%u6CA1%u6CD5%u52A0%u8F7D%u914D%u7F6E%u6570%u636E%u3002%0A%0AXposed%u5B98%u65B9%u6216%u8005%u4F5C%u8005rovo89%u8FD8%u6CA1%u6709%u7ED9%u51FA%u5B98%u65B9%u7684%u89E3%u51B3%u529E%u6CD5%uFF0C%u4F46%u603B%u662F%u4F1A%u6709%u4E00%u4E9B%u672A%u96E8%u7EF8%u7F2A%u7684%u52C7%u58EB%uFF0CXDA%u4E0A%u6709%u4E00%u4E2A%u5E16%u5B50%u7ED9%u51FA%u4E86%u4E00%u4E2Awork%20around%uFF1A%5BMODE_WORLD_READABLE%20in%20Android%20N%5D%28https%3A//forum.xda-developers.com/xposed/development/modeworldreadable-android-n-t3407123%29%0A%0A%u6211%u5728Niwatori%u4E2D%u4E5F%u4F7F%u7528%u4E86%u8BE5%u65B9%u6CD5%uFF0C%u4F46%u4ECD%u7136%u4E0D%u662F%u5B8C%u7F8E%u89E3%u51B3%uFF0C%u800C%u4E14%u76EE%u524D%u8FD8%u4E0D%u77E5%u9053%u5982%u4F55%u6539%u8FDB%u3002%0A%0A%23%23%20%u9057%u7559%u7684%u95EE%u9898%0A%u8BE5work%20around%u548CXSharedPreference.makeWorldReadable%u540C%u7406%uFF0C%u6211%u5982%u4E0B%u8C03%u7528preference%uFF1A%0A%60%60%60%0AmPrefs.makeWorldReadable%28%29%3B%0ALog.e%28%22Ben%22%2C%20%22package%3A%22%20+%20decorView.getContext%28%29.getPackageName%28%29%20+%20%22%2C%20%22%20+%20decorView%20+%20%22%2C%22%20+%20mPrefs.getString%28%22key_boundary_color_ms%22%2C%20%22default%20value%22%29%29%3B%0ALog.e%28%22Ben%22%2C%20%22file%20can%20read%3A%20%22%20+%20mPrefs.getFile%28%29.canRead%28%29%29%3B%20%3C--%20%u6709%u4E9Bapp%u4F1A%u662Ftrue%uFF0C%u6709%u4E9Bapp%u4F1A%u662Ffalse%0A%60%60%60%0A%u5F53%u8FD4%u56DEtrue%u7684%u65F6%u5019%uFF0Csettings%u5C31%u6210%u529F%u7684%u4F20%u5230%u4E86%u5BF9%u5E94app%u4E86%u3002%u8FD9%u4E2A%u65F6%u800C%u53EF%u4EE5read%u65F6%u800C%u4E0D%u53EF%u4EE5read%uFF0C%u6211%u4E5F%u5F88%u82E6%u607C%uFF0C%u4E0D%u77E5%u9053%u662F%u600E%u4E48%u56DE%u4E8B%u513F%u3002%u7559%u5F85%u4EE5%u540E%u518D%u89E3%u51B3%u4E86%u3002%0A%0A%23%23%20%u89E3%u51B3%u9057%u7559%u7684%u95EE%u9898%20-%2020180119%0A%u4EE5%u4E0A%u7684%u95EE%u9898%u5728%u4E8E%uFF0CAndroid%207.0%u5F00%u59CB%uFF0C%u5373%u4ECESDK%2024%u5F00%u59CB%uFF0CAndroid%u52A0%u5165%u4E86%u5F88%u591Asecurity%u65B9%u9762%u7684%u7279%u6027%uFF0C%u53C2%u8003%5BAndroid%207.0%20Security%20Features%3A%20Direct%20Boot%5D%28https%3A//blog.compass-security.com/2016/10/android-7-0-security-features-direct-boot/%29%u3002%u8FD9%u548C%u6211%u4EEC%u7684%u95EE%u9898%u4E0D%u592A%u76F8%u5173%u3002%u76F8%u5173%u7684%u662F%u5982%u4E0A%u6240%u8BF4%uFF0CNougat%u4E0D%u5141%u8BB8world%20readable%u7684%u6587%u4EF6%u4E86%u3002%u5982%u679C%u7528SDK25%u7F16%u8BD1%u7684app%u8FD8%u7528%60MODE_WORLD_READABLE%60%uFF0C%u7CFB%u7EDF%u4F1A%u62A5exception%u3002%0AGoogle%u4E0A%u9C9C%u5C11%u6709%u76F8%u5173%u7684%u89E3%u51B3%u65B9%u6848%uFF0C%u6709%u5982%u4E0B%u51E0%u4E2A%u94FE%u63A5%u53EF%u4EE5%u53C2%u8003%uFF1A%0A-%20%5BGravityBox%20commit%20-%20Use%20device%20protected%20storage%20for%20preferences%20and%20files%5D%28https%3A//github.com/GravityBox/GravityBox/commit/d825b7be445c18de9a90eb8f77c1c5eb2b74deb8%29%0A-%20%5BXposedBridge%20issue%201%20-%20Any%20place%20to%20store%20world%20readable%20preferences%20on%20Nougat%3F%5D%28https%3A//github.com/rovo89/XposedBridge/issues/206%29%0A-%20%5BXposedBridge%20issue%202%20-%20Preferences%20of%20a%20module%20cannot%20be%20read%20from%20different%20process%20on%20some%20devices%20running%20MM%5D%28https%3A//github.com/rovo89/XposedBridge/issues/74%29%0A-%20%5BXposedBridge%20issue%203%20-%20XSharedPreferences%20doesn%27t%20work%5D%28https%3A//github.com/rovo89/XposedBridge/issues/102%29%0A-%20%5B%5BQ%5D%20Xposed%20for%20nougat%20to%20read%20prefs%20ith%20fbe%20or%20without%5D%28https%3A//forum.xda-developers.com/xposed/xposed-nougat-to-read-prefs-ith-fbe-t3690048%29%0A%0A%u7ECF%u8FC7%u9A8C%u8BC1%uFF0C%u662FXposedBridge%20issue%201%u4E2DGravityBox%u4F5C%u8005%u7684%u4E00%u4E2Acomment%u63D0%u5230%u4E86%u6700%u7EC8%u7684%u89E3%u51B3%u65B9%u6CD5%u3002%u8BE5comment%u5982%u4E0B%uFF1A%0A%21%5BAlt%20text%5D%28./1516334231370.png%29%0A%u5728%u4E0A%u9762XDA%u7684%u5E16%u5B50%uFF0C%u4EE5%u53CAGravityBox%u7684commit%u4E2D%uFF0C%u6211%u4EEC%u53EF%u4EE5%u770B%u5230GravityBox%u7684%u4F5C%u8005%u91C7%u7528%u4E86Android%207.0%u4E2D%u65B0%u7684SharedPreference%u5B58%u50A8%u65B9%u5F0F%uFF0C%u5373%u901A%u8FC7%u4E0B%u9762%u4E24%u4E2A%u51FD%u6570%uFF1A%0A-%20%60setStorageDeviceProtected%60%0A-%20%60createDeviceProtectedStorageContext%60%0A%0A%u5C06preference%u6587%u4EF6%u5B58%u5230%60/data/user_de/0/%3Cpackage%20name%3E/shared_prefs%60%u4E0B%u3002%u5E76%u5728Xposed%u7684context%u7AEF%uFF0C%u76F4%u63A5%u6253%u5F00%u6587%u4EF6%u8FDB%u884C%u64CD%u4F5C%u3002%0A%u4F46%u5176%u5B9E%u6211%u4EEC%u5E76%u4E0D%u9700%u5982%u6B64%u3002%u53EA%u8981%u4FDD%u8BC1package%20folder%u7684%u6743%u9650%u81F3%u5C11%u662F711%uFF0Cpreference.xml%u6587%u4EF6%u6709%u53EF%u8BFB%u6743%u9650%u5373%u53EF%u3002%0A

Edit

最近在维护一个Xposed模块[]Niwatori-One Handed Mode](https://github.com/tkgktyk/Niwatori)。原作者tkgktyk已经停止更新了,导致模块在Xposed Framework for Nougat发布以后,不能使用。于是我fork了一份代码,开始做Android Nougat上的适配工作,并在XDA上发布了更新链接
在适配了Nougat之后,希望能添加一些新功能,让用户体验更好。目前想做的是能通过fooview调用Niwatori的快捷方式。并且该快捷方式的功能,例如是small screen还是slide down等等,能通过Niwatori本身进行配置。但是在开发这一功能的时候,发现动态快捷方式的加载需要使用SDK 25以上版本,而从SDK 25开始,原先SharedPreference的打开方式MODE_WORLD_PRIVATE已经被禁止了。使用它会导致security exception。
所以要升到使用SDK 25,必须解决preference引用的问题。那么这个模式的变化,到底会在哪里影响到我们的Xposed模块呢?

Xposed中的preference

Xposed模块中使用preference的时候,通常都是通过XSharedPreference来操作。XSharedPreference在Android标准的SharedPreference类上包了一层,提供了一些security的fix或者work around。例如:XSharedPreference.makeWorldReadable。他们都是加载app data文件夹下的xml文件来读取、存储键值对的。该文件路径为(以Niwatori为例):/data/data/jp.tkgktyk.xposed.niwatori/shared_prefs/jp.tkgktyk.xposed.niwatori_preferences.xml

通常Xposed中如下使用preference会按照如下的时序图,以Niwatori为例:

  • XSharedPreference实例创建在模块加载的initZygote
  • 数据的使用通过钩子函数,在各个app的Context底下执行

于是当MODE_WORLD_READABLE被废止以后,这里就出问题了。即在默认情况下,app1是没有权限查看Niwatori的preference文件的,也就没法加载配置数据。

Xposed官方或者作者rovo89还没有给出官方的解决办法,但总是会有一些未雨绸缪的勇士,XDA上有一个帖子给出了一个work around:MODE_WORLD_READABLE in Android N

我在Niwatori中也使用了该方法,但仍然不是完美解决,而且目前还不知道如何改进。

遗留的问题

该work around和XSharedPreference.makeWorldReadable同理,我如下调用preference:

mPrefs.makeWorldReadable();
Log.e("Ben", "package:" + decorView.getContext().getPackageName() + ", " + decorView + "," + mPrefs.getString("key_boundary_color_ms", "default value"));
Log.e("Ben", "file can read: " + mPrefs.getFile().canRead()); <-- 有些app会是true,有些app会是false

当返回true的时候,settings就成功的传到了对应app了。这个时而可以read时而不可以read,我也很苦恼,不知道是怎么回事儿。留待以后再解决了。

解决遗留的问题 - 20180119

以上的问题在于,Android 7.0开始,即从SDK 24开始,Android加入了很多security方面的特性,参考Android 7.0 Security Features: Direct Boot。这和我们的问题不太相关。相关的是如上所说,Nougat不允许world readable的文件了。如果用SDK25编译的app还用MODE_WORLD_READABLE,系统会报exception。
Google上鲜少有相关的解决方案,有如下几个链接可以参考:

经过验证,是XposedBridge issue 1中GravityBox作者的一个comment提到了最终的解决方法。该comment如下:

  • setStorageDeviceProtected
  • createDeviceProtectedStorageContext

将preference文件存到/data/user_de/0/<package name>/shared_prefs下。并在Xposed的context端,直接打开文件进行操作。
但其实我们并不需如此。只要保证package folder的权限至少是711,preference.xml文件有可读权限即可。

%23%20XSharedPreference%20%26%20SharedPreference%20-%20XPosed%u6A21%u5757%u4E2D%u7684preference%u4F7F%u7528%0A@%28myblog%29%5BAndroid%2C%20xposed%5D%0A%0A%u6700%u8FD1%u5728%u7EF4%u62A4%u4E00%u4E2AXposed%u6A21%u5757%5B%5DNiwatori-One%20Handed%20Mode%5D%28https%3A//github.com/tkgktyk/Niwatori%29%u3002%u539F%u4F5C%u8005tkgktyk%u5DF2%u7ECF%u505C%u6B62%u66F4%u65B0%u4E86%uFF0C%u5BFC%u81F4%u6A21%u5757%u5728Xposed%20Framework%20for%20Nougat%u53D1%u5E03%u4EE5%u540E%uFF0C%u4E0D%u80FD%u4F7F%u7528%u3002%u4E8E%u662F%u6211fork%u4E86%u4E00%u4EFD%u4EE3%u7801%uFF0C%u5F00%u59CB%u505AAndroid%20Nougat%u4E0A%u7684%u9002%u914D%u5DE5%u4F5C%uFF0C%u5E76%u5728XDA%u4E0A%u53D1%u5E03%u4E86%u66F4%u65B0%5B%u94FE%u63A5%5D%28https%3A//forum.xda-developers.com/xposed/modules/mod-niwatori-one-handed-mode-t3730963%29%u3002%0A%u5728%u9002%u914D%u4E86Nougat%u4E4B%u540E%uFF0C%u5E0C%u671B%u80FD%u6DFB%u52A0%u4E00%u4E9B%u65B0%u529F%u80FD%uFF0C%u8BA9%u7528%u6237%u4F53%u9A8C%u66F4%u597D%u3002%u76EE%u524D%u60F3%u505A%u7684%u662F%u80FD%u901A%u8FC7fooview%u8C03%u7528Niwatori%u7684%u5FEB%u6377%u65B9%u5F0F%u3002%u5E76%u4E14%u8BE5%u5FEB%u6377%u65B9%u5F0F%u7684%u529F%u80FD%uFF0C%u4F8B%u5982%u662Fsmall%20screen%u8FD8%u662Fslide%20down%u7B49%u7B49%uFF0C%u80FD%u901A%u8FC7Niwatori%u672C%u8EAB%u8FDB%u884C%u914D%u7F6E%u3002%u4F46%u662F%u5728%u5F00%u53D1%u8FD9%u4E00%u529F%u80FD%u7684%u65F6%u5019%uFF0C%u53D1%u73B0%u52A8%u6001%u5FEB%u6377%u65B9%u5F0F%u7684%u52A0%u8F7D%u9700%u8981%u4F7F%u7528SDK%2025%u4EE5%u4E0A%u7248%u672C%uFF0C%u800C%u4ECESDK%2025%u5F00%u59CB%uFF0C%u539F%u5148SharedPreference%u7684%u6253%u5F00%u65B9%u5F0FMODE%5C_WORLD%5C_PRIVATE%u5DF2%u7ECF%u88AB%u7981%u6B62%u4E86%u3002%u4F7F%u7528%u5B83%u4F1A%u5BFC%u81F4security%20exception%u3002%0A%u6240%u4EE5%u8981%u5347%u5230%u4F7F%u7528SDK%2025%uFF0C%u5FC5%u987B%u89E3%u51B3preference%u5F15%u7528%u7684%u95EE%u9898%u3002%u90A3%u4E48%u8FD9%u4E2A%u6A21%u5F0F%u7684%u53D8%u5316%uFF0C%u5230%u5E95%u4F1A%u5728%u54EA%u91CC%u5F71%u54CD%u5230%u6211%u4EEC%u7684Xposed%u6A21%u5757%u5462%uFF1F%0A%0A%23%23%20Xposed%u4E2D%u7684preference%0AXposed%u6A21%u5757%u4E2D%u4F7F%u7528preference%u7684%u65F6%u5019%uFF0C%u901A%u5E38%u90FD%u662F%u901A%u8FC7XSharedPreference%u6765%u64CD%u4F5C%u3002XSharedPreference%u5728Android%u6807%u51C6%u7684SharedPreference%u7C7B%u4E0A%u5305%u4E86%u4E00%u5C42%uFF0C%u63D0%u4F9B%u4E86%u4E00%u4E9Bsecurity%u7684fix%u6216%u8005work%20around%u3002%u4F8B%u5982%uFF1AXSharedPreference.makeWorldReadable%u3002%u4ED6%u4EEC%u90FD%u662F%u52A0%u8F7Dapp%20data%u6587%u4EF6%u5939%u4E0B%u7684xml%u6587%u4EF6%u6765%u8BFB%u53D6%u3001%u5B58%u50A8%u952E%u503C%u5BF9%u7684%u3002%u8BE5%u6587%u4EF6%u8DEF%u5F84%u4E3A%uFF08%u4EE5Niwatori%u4E3A%u4F8B%uFF09%uFF1A%60/data/data/jp.tkgktyk.xposed.niwatori/shared_prefs/jp.tkgktyk.xposed.niwatori_preferences.xml%60%u3002%0A%0A%u901A%u5E38Xposed%u4E2D%u5982%u4E0B%u4F7F%u7528preference%u4F1A%u6309%u7167%u5982%u4E0B%u7684%u65F6%u5E8F%u56FE%uFF0C%u4EE5Niwatori%u4E3A%u4F8B%uFF1A%0A%60%60%60%20sequence%0ANote%20left%20of%20Niwatori%3A%20initZygote%0ANote%20left%20of%20Niwatori%3A%20Construct%20a%20XSharedPreference%0ANiwatori-%3EActivity.class%3A%20hook%0AActivity.class-%3Eapp1%3A%20onCreate%0ANote%20right%20of%20app1%3A%20load%20the%20XSharedPreference%0AActivity.class-%3Eapp2%3A%20onCreate%0ANote%20right%20of%20app2%3A%20load%20the%20XSharedPreference%0A%60%60%60%0A-%20XSharedPreference%u5B9E%u4F8B%u521B%u5EFA%u5728%u6A21%u5757%u52A0%u8F7D%u7684%60initZygote%60%u4E2D%0A-%20%u6570%u636E%u7684%u4F7F%u7528%u901A%u8FC7%u94A9%u5B50%u51FD%u6570%uFF0C%u5728%u5404%u4E2Aapp%u7684Context%u5E95%u4E0B%u6267%u884C%0A%0A%u4E8E%u662F%u5F53MODE%5C_WORLD%5C_READABLE%u88AB%u5E9F%u6B62%u4EE5%u540E%uFF0C%u8FD9%u91CC%u5C31%u51FA%u95EE%u9898%u4E86%u3002%u5373%u5728%u9ED8%u8BA4%u60C5%u51B5%u4E0B%uFF0Capp1%u662F%u6CA1%u6709%u6743%u9650%u67E5%u770BNiwatori%u7684preference%u6587%u4EF6%u7684%uFF0C%u4E5F%u5C31%u6CA1%u6CD5%u52A0%u8F7D%u914D%u7F6E%u6570%u636E%u3002%0A%0AXposed%u5B98%u65B9%u6216%u8005%u4F5C%u8005rovo89%u8FD8%u6CA1%u6709%u7ED9%u51FA%u5B98%u65B9%u7684%u89E3%u51B3%u529E%u6CD5%uFF0C%u4F46%u603B%u662F%u4F1A%u6709%u4E00%u4E9B%u672A%u96E8%u7EF8%u7F2A%u7684%u52C7%u58EB%uFF0CXDA%u4E0A%u6709%u4E00%u4E2A%u5E16%u5B50%u7ED9%u51FA%u4E86%u4E00%u4E2Awork%20around%uFF1A%5BMODE_WORLD_READABLE%20in%20Android%20N%5D%28https%3A//forum.xda-developers.com/xposed/development/modeworldreadable-android-n-t3407123%29%0A%0A%u6211%u5728Niwatori%u4E2D%u4E5F%u4F7F%u7528%u4E86%u8BE5%u65B9%u6CD5%uFF0C%u4F46%u4ECD%u7136%u4E0D%u662F%u5B8C%u7F8E%u89E3%u51B3%uFF0C%u800C%u4E14%u76EE%u524D%u8FD8%u4E0D%u77E5%u9053%u5982%u4F55%u6539%u8FDB%u3002%0A%0A%23%23%20%u9057%u7559%u7684%u95EE%u9898%0A%u8BE5work%20around%u548CXSharedPreference.makeWorldReadable%u540C%u7406%uFF0C%u6211%u5982%u4E0B%u8C03%u7528preference%uFF1A%0A%60%60%60%0AmPrefs.makeWorldReadable%28%29%3B%0ALog.e%28%22Ben%22%2C%20%22package%3A%22%20+%20decorView.getContext%28%29.getPackageName%28%29%20+%20%22%2C%20%22%20+%20decorView%20+%20%22%2C%22%20+%20mPrefs.getString%28%22key_boundary_color_ms%22%2C%20%22default%20value%22%29%29%3B%0ALog.e%28%22Ben%22%2C%20%22file%20can%20read%3A%20%22%20+%20mPrefs.getFile%28%29.canRead%28%29%29%3B%20%3C--%20%u6709%u4E9Bapp%u4F1A%u662Ftrue%uFF0C%u6709%u4E9Bapp%u4F1A%u662Ffalse%0A%60%60%60%0A%u5F53%u8FD4%u56DEtrue%u7684%u65F6%u5019%uFF0Csettings%u5C31%u6210%u529F%u7684%u4F20%u5230%u4E86%u5BF9%u5E94app%u4E86%u3002%u8FD9%u4E2A%u65F6%u800C%u53EF%u4EE5read%u65F6%u800C%u4E0D%u53EF%u4EE5read%uFF0C%u6211%u4E5F%u5F88%u82E6%u607C%uFF0C%u4E0D%u77E5%u9053%u662F%u600E%u4E48%u56DE%u4E8B%u513F%u3002%u7559%u5F85%u4EE5%u540E%u518D%u89E3%u51B3%u4E86%u3002%0A%0A%23%23%20%u89E3%u51B3%u9057%u7559%u7684%u95EE%u9898%20-%2020180119%0A%u4EE5%u4E0A%u7684%u95EE%u9898%u5728%u4E8E%uFF0CAndroid%207.0%u5F00%u59CB%uFF0C%u5373%u4ECESDK%2024%u5F00%u59CB%uFF0CAndroid%u52A0%u5165%u4E86%u5F88%u591Asecurity%u65B9%u9762%u7684%u7279%u6027%uFF0C%u53C2%u8003%5BAndroid%207.0%20Security%20Features%3A%20Direct%20Boot%5D%28https%3A//blog.compass-security.com/2016/10/android-7-0-security-features-direct-boot/%29%u3002%u8FD9%u548C%u6211%u4EEC%u7684%u95EE%u9898%u4E0D%u592A%u76F8%u5173%u3002%u76F8%u5173%u7684%u662F%u5982%u4E0A%u6240%u8BF4%uFF0CNougat%u4E0D%u5141%u8BB8world%20readable%u7684%u6587%u4EF6%u4E86%u3002%u5982%u679C%u7528SDK25%u7F16%u8BD1%u7684app%u8FD8%u7528%60MODE_WORLD_READABLE%60%uFF0C%u7CFB%u7EDF%u4F1A%u62A5exception%u3002%0AGoogle%u4E0A%u9C9C%u5C11%u6709%u76F8%u5173%u7684%u89E3%u51B3%u65B9%u6848%uFF0C%u6709%u5982%u4E0B%u51E0%u4E2A%u94FE%u63A5%u53EF%u4EE5%u53C2%u8003%uFF1A%0A-%20%5BGravityBox%20commit%20-%20Use%20device%20protected%20storage%20for%20preferences%20and%20files%5D%28https%3A//github.com/GravityBox/GravityBox/commit/d825b7be445c18de9a90eb8f77c1c5eb2b74deb8%29%0A-%20%5BXposedBridge%20issue%201%20-%20Any%20place%20to%20store%20world%20readable%20preferences%20on%20Nougat%3F%5D%28https%3A//github.com/rovo89/XposedBridge/issues/206%29%0A-%20%5BXposedBridge%20issue%202%20-%20Preferences%20of%20a%20module%20cannot%20be%20read%20from%20different%20process%20on%20some%20devices%20running%20MM%5D%28https%3A//github.com/rovo89/XposedBridge/issues/74%29%0A-%20%5BXposedBridge%20issue%203%20-%20XSharedPreferences%20doesn%27t%20work%5D%28https%3A//github.com/rovo89/XposedBridge/issues/102%29%0A-%20%5B%5BQ%5D%20Xposed%20for%20nougat%20to%20read%20prefs%20ith%20fbe%20or%20without%5D%28https%3A//forum.xda-developers.com/xposed/xposed-nougat-to-read-prefs-ith-fbe-t3690048%29%0A%0A%u7ECF%u8FC7%u9A8C%u8BC1%uFF0C%u662FXposedBridge%20issue%201%u4E2DGravityBox%u4F5C%u8005%u7684%u4E00%u4E2Acomment%u63D0%u5230%u4E86%u6700%u7EC8%u7684%u89E3%u51B3%u65B9%u6CD5%u3002%u8BE5comment%u5982%u4E0B%uFF1A%0A%21%5BAlt%20text%5D%28./1516334231370.png%29%0A%u5728%u4E0A%u9762XDA%u7684%u5E16%u5B50%uFF0C%u4EE5%u53CAGravityBox%u7684commit%u4E2D%uFF0C%u6211%u4EEC%u53EF%u4EE5%u770B%u5230GravityBox%u7684%u4F5C%u8005%u91C7%u7528%u4E86Android%207.0%u4E2D%u65B0%u7684SharedPreference%u5B58%u50A8%u65B9%u5F0F%uFF0C%u5373%u901A%u8FC7%u4E0B%u9762%u4E24%u4E2A%u51FD%u6570%uFF1A%0A-%20%60setStorageDeviceProtected%60%0A-%20%60createDeviceProtectedStorageContext%60%0A%0A%u5C06preference%u6587%u4EF6%u5B58%u5230%60/data/user_de/0/%3Cpackage%20name%3E/shared_prefs%60%u4E0B%u3002%u5E76%u5728Xposed%u7684context%u7AEF%uFF0C%u76F4%u63A5%u6253%u5F00%u6587%u4EF6%u8FDB%u884C%u64CD%u4F5C%u3002%0A%u4F46%u5176%u5B9E%u6211%u4EEC%u5E76%u4E0D%u9700%u5982%u6B64%u3002%u53EA%u8981%u4FDD%u8BC1package%20folder%u7684%u6743%u9650%u81F3%u5C11%u662F711%uFF0Cpreference.xml%u6587%u4EF6%u6709%u53EF%u8BFB%u6743%u9650%u5373%u53EF%u3002%0A