看板 C_and_CPP 關於我們 聯絡資訊
先回答你的問題 首先一個觀念, shared_ptr 跟 unique_ptr 的設計 就是你可以把這個變數「當成指向物件的指標變數來使用」 例如對 Foo* pFoo = new Foo(); 可以 pFoo->bar(); 那 shared_ptr<Foo> spFoo (new Foo()); 也就可以 spFoo->bar(); 不過上面那句「當成」有個但書是「你不能對它進行指標算術 (包含陣列存取)」 因為概念上這些東西是用來管理一個物件的, 對這物件之外的地方存取沒有意義 所以雖然可以 *spFoo 取得所管理的物件, 但不能寫 spFoo[0] 做陣列存取 ==== 那麼這裡就要回到你一開始的指標版本了 你在宣告了 std::vector<std::vector<int>> *p = ...; 之後 下面直接使用了 p[0] 去取得這個物件 (像是 p[0].size() 去取得外層長度, 或 p[0][0] 取得第一列等等) 雖然你取到了, 但這只是因為它是指標變數所以 *p 等同 p[0] 而已 這裡正確的取法是要使用 *p 去取得物件 (它又不指向一個陣列為什麼要 [0] ?) (也就是像上面那個要寫成 (*p).size() 和 (*p)[0] 才對) 這即是造成了你換成 shared_ptr 之後編譯不過的原因 不然理論上指標版本的程式碼跟 shared_ptr / unique_ptr 版本的程式碼 應該是無痛轉換的才對 ==== 然而 (這裡算是一部份的題外話) 使用動態配置產生一個 vector 物件是有點疊床架屋的 因為 vector 自己本身就是使用動態配置來配置它的陣列內容的 (也因此才能夠隨意增加長度) vector 的本體其實相對很小, 沒記錯應該等同數個 int 大小而已 傳來傳去的成本也並不高 這也就是為什麼推文一開始在問你「為什麼不直接宣告 vector 物件」的原因 ==== 再延伸出去一點 相對於 shared_ptr / unique_ptr 是對「(動態配置物件的)指標」的包裝 vector 則是對「(動態配置的)陣列」的包裝 也就是設計上 vector 才是使用陣列的存取方式 (也就是 [] 的方式) 這同時也呼應到版上常常看到很多人在講的「指標不等於陣列」這句話 對一般的指標來說, 雖然編譯到底層的機械碼是一樣的, 但上層的語意不同 而 shared_ptr / unique_ptr 跟 vector 即是分別抓取這兩種語意做為存取介面 因此在使用時不能混用這兩種存取介面 -- 有人喜歡邊玩遊戲上逼; 也有人喜歡邊聽歌打字。 但是,我有個請求, 選字的時候請專心好嗎? -- 改編自「古 火田 任三郎」之開場白 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 123.195.9.46 ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1506618874.A.FFC.html
PkmX: std::{shared,unique}_ptr之後可以用在T[]上 09/29 03:58
LPH66: 關於這個, https://stackoverflow.com/a/16804634 這個回答 09/29 09:40
LPH66: 比較了 std::vector, std::array 跟 std::unique_ptr<T[]> 09/29 09:41
LPH66: 它們的各個方面, 三種各擅勝場在有相對的需求時確實好用 09/29 09:42
LPH66: 所以我這篇文章比較沒有著重在哪個狀況要用哪個 09/29 09:43
LPH66: 而是在解釋它們的設計概念跟語意 09/29 09:44
LPH66: 再說我也沒有完全否定 shared_ptr<vector<T>> 就是 09/29 09:45