Re: [問題] std::shared_ptr std::vector

作者: LPH66 (-6.2598534e+18f)   2017-09-29 01:14:32
先回答你的問題
首先一個觀念, 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 即是分別抓取這兩種語意做為存取介面
因此在使用時不能混用這兩種存取介面
作者: PkmX (阿貓)   2017-09-29 03:58:00
std::{shared,unique}_ptr之後可以用在T[]上http://coliru.stacked-crooked.com/a/f17781559d36eb92
作者: LPH66 (-6.2598534e+18f)   2017-09-29 09:40:00
關於這個, https://stackoverflow.com/a/16804634 這個回答比較了 std::vector, std::array 跟 std::unique_ptr<T[]>它們的各個方面, 三種各擅勝場在有相對的需求時確實好用所以我這篇文章比較沒有著重在哪個狀況要用哪個而是在解釋它們的設計概念跟語意再說我也沒有完全否定 shared_ptr<vector<T>> 就是

Links booklink

Contact Us: admin [ a t ] ucptt.com