我比較了 Goappend函數和 STL vector.push_back,發現不同的內存分配策略讓我很困惑。代碼如下:// CPP STL codevoid getAlloc() { vector<double> arr; int s = 9999999; int precap = arr.capacity(); for (int i=0; i<s; i++) { if (precap < i) { arr.push_back(rand() % 12580 * 1.0); precap = arr.capacity(); printf("%d %p\n", precap, &arr[0]); } else { arr.push_back(rand() % 12580 * 1.0); } } printf("\n"); return;}// Golang code func getAlloc() { arr := []float64{} size := 9999999 pre := cap(arr) for i:=0; i<size; i++ { if pre < i { arr = append(arr, rand.NormFloat64()) pre = cap(arr) log.Printf("%d %p\n", pre, &arr) } else { arr = append(arr, rand.NormFloat64()) } } return;}但是內存地址對于大小的增量是不變的,這讓我很困惑。順便說一句,這兩種實現(STL VS. Go)的內存分配策略不同,我的意思是擴展大小。有什么優點或缺點嗎?這是上面代碼的簡化輸出[大小和第一個元素地址]:Golang CPP STL2 0xc0800386c0 2 004B19C04 0xc0800386c0 4 004AE9B88 0xc0800386c0 6 004B29E016 0xc0800386c0 9 004B2A1832 0xc0800386c0 13 004B2A6864 0xc0800386c0 19 004B2AD8128 0xc0800386c0 28 004B29E0256 0xc0800386c0 42 004B2AC8512 0xc0800386c0 63 004B2C201024 0xc0800386c0 94 004B2E201280 0xc0800386c0 141 004B31181600 0xc0800386c0 211 004B29E02000 0xc0800386c0 316 004B30802500 0xc0800386c0 474 004B3A683125 0xc0800386c0 711 004B5FD03906 0xc0800386c0 1066 004B7610
2 回答
達令說
TA貢獻1821條經驗 獲得超6個贊
你的 Go 和 C++ 代碼片段不是等價的。在 C++ 函數中,您正在打印向量中第一個元素的地址,而在 Go 示例中,您正在打印切片本身的地址。
與 C++ 一樣std::vector,Go 切片是一種小型數據類型,它包含一個指向包含數據的底層數組的指針。該數據結構在整個函數中具有相同的地址。如果你想在片中的第一元素的地址,你可以使用相同的語法與C ++: &arr[0]。
慕哥9229398
TA貢獻1877條經驗 獲得超6個贊
您正在獲取指向切片標頭的指針,而不是實際的支持數組。您可以將切片標頭視為一個結構,例如
type SliceHeader struct {
len,cap int
backingArray unsafe.Pointer
}
當您追加并重新分配后備數組時,指針backingArray可能會更改(不一定,但可能)。但是,保存長度、上限和指向后備數組的指針的結構的位置不會改變——它仍然在你聲明它的堆棧上。嘗試打印&arr[0]而不是,&arr您應該會看到更接近您期望的行為。
std::vector順便說一下,這與 的行為幾乎相同。將切片視為vector比魔術動態數組更接近 a 。
- 2 回答
- 0 關注
- 294 瀏覽
添加回答
舉報
0/150
提交
取消
