C++ 向程序員提供了在堆或堆棧中分配對象的選擇。基于堆棧的分配更有效:分配更便宜,回收成本真正為零,而且語言提供了隔離對象生命周期的幫助,減少了忘記釋放對象的風險。另一方面,在 C++ 中,在發布或共享基于堆棧的對象的引用時,必須非常小心,因為在堆棧幀整理時,基于堆棧的對象會被自動釋放,從而造成孤懸的指針。
清單 2 顯示了一個可以用 escape 分析把堆分配優化掉的示例。Component.getLocation() 方法對組件的位置做了一個保護性的拷貝,這樣調用者就無法在不經意間改變組件的實際位置。先調用 getDistanceFrom() 得到另一個組件的位置,其中包括對象的分配,然后用 getLocation() 返回的 Point 的 x 和 y 字段計算兩個組件之間的距離。
清單 2. 返回復合值的典型的保護性拷貝方式
public class Point { PRivate int x, y; public Point(int x, int y) { this.x = x; this.y = y; } public Point(Point p) { this(p.x, p.y); } public int getX() { return x; } public int getY() { return y; } }
public class Component { private Point location; public Point getLocation() { return new Point(location); }
public double getDistanceFrom(Component other) { Point otherLocation = other.getLocation(); int deltaX = otherLocation.getX() - location.getX(); int deltaY = otherLocation.getY() - location.getY(); return Math.sqrt(deltaX*deltaX + deltaY*deltaY); } }
getLocation() 方法不知道它的調用者要如何處理它返回的 Point;有可能得到一個指向 Point 的引用,比如把它放在集合中,所以 getLocation() 采用了保護性的編碼方式。但是,在這個示例中,getDistanceFrom() 并不會這么做,它只會使用 Point 很短的時間,然后釋放它,這看起來像是對完美對象的浪費。