Solidity

將結構推送到包含數組本身的數組

  • February 18, 2018

我正在閱讀這篇文章,其中給出了一個不起作用的契約範例。雖然他們已經在文章中修復了它,但我想知道為什麼它不起作用。我在下面複製了一個簡化版本:

pragma solidity ^0.4.18;

contract StructArrayInitWrong {
 struct Room {
   address[] players;       
 }  
 Room[] rooms;

 function createRoom() public {
   address[] adr;
   adr.push(msg.sender);
   Room memory room = Room(adr);   
   rooms.push(room);
 }

 function getRoomsLength() view returns (uint) {
   return rooms.length;
 }
}

奇怪的是,在這個合約中rooms每次createRoom呼叫數組長度都會增加兩倍。你能解釋一下這種行為嗎?謝謝。

問題在於這條線

address[] adr;

有一個關於未初始化儲存的“警告”。這裡發生的事情比溫和的警告可能暗示的要多。我真的不明白為什麼這不是一個硬錯誤,所以開發人員不接受它。

由於儲存未初始化,編譯器不知道將動態數組放在哪裡,adr[]因此將其放在第一個 slot中。你沒看錯。它在跺腳rooms[]。哎喲!

由於該槽的佔用者也恰好是一個動態數組,因此它也使用第一個詞來描述數組長度。因此,我們得到了觀察到的奇怪行為……推到一個數組,然後推到另一個,然後噗!- 兩個數組的長度都是 2。

這不是在函式內部而不是在通常的位置(外部)聲明的儲存導致潛在的災難性數據覆蓋的唯一情況。另一個例子見這裡:Solc 編譯器監督?不適當的映射聲明會覆蓋儲存

考慮到智能合約應該是清晰且沒有缺陷的,我不喜歡這種意想不到的結果。這和參考變數加起來對我來說有點太多巫術了。

也許其他人會加入更好的啟發式方法。我可能建議養成兩個習慣

這是一個更改並按預期工作的程式碼:

pragma solidity ^0.4.18;

contract StructArrayInitWrong {

 struct Room {
   address[] players;       
 }  
 Room[] rooms;
 address[] adr; // <=== if we're going to store this, then let's store this.

 function createRoom() public {
                                   // <=== note gaping hole
   adr.push(msg.sender);
   Room memory room = Room(adr);   
   rooms.push(room);
 }

 function getRoomsLength() public view returns (uint) {
   return rooms.length;
 }
}

希望能幫助到你。

引用自:https://ethereum.stackexchange.com/questions/40045