จะจัดเก็บพอยน์เตอร์ไปยังวัตถุที่จัดสรรแบบคงที่ในเวกเตอร์ได้อย่างไร

ให้บอกว่าฉันต้องการสร้างเวกเตอร์ของวัตถุและเวกเตอร์ของตัวชี้อีกตัวไปยังวัตถุเหล่านั้น (ฉันไม่สามารถใช้หน่วยความจำแบบไดนามิกได้) วิธีที่ฉันจะทำคือในตัวอย่างต่อไปนี้

#include <iostream>
#include <vector>

using namespace std;

class Foo {
public:
  int bar;
  Foo(int x) : bar(x) {
  }
};

int main () {
  vector<Foo> foos;
  vector<Foo*> pFoos;
  for (int i = 0; i < 10; i++) {
    Foo foo(i);
    foos.push_back(foo);
    pFoos.push_back(&foos.back());
  }

  for (int i = 0; i < 10; i++) {
    cout << foos[i].bar << endl;
    cout << pFoos[i]->bar << endl;
  }
}

ฉันคิดว่าสิ่งนี้น่าจะได้ผลเพราะ foos เก็บสำเนาของออบเจ็กต์ จากนั้นฉันก็เก็บการอ้างอิงไปยังสำเนานั้น (เพราะว่า foo ต้นฉบับจะไม่ได้กำหนดไว้ ดังนั้นฉันจึงไม่ควรเก็บข้อมูลอ้างอิงถึงสิ่งนั้น) แต่นี่คือสิ่งที่ฉันได้รับ:

0
36741184
1
0
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9

เลขตัวแรกถึงตัวเลขจาก pFoos ผิด นอกจากนี้จำนวนมากยังเปลี่ยนแปลงทุกครั้ง ฉันไม่เห็นสิ่งใดที่จะทำให้เกิดพฤติกรรมที่ไม่ได้กำหนดนี้ ใครช่วยบอกฉันว่าฉันทำอะไรผิด?


person gsingh2011    schedule 12.11.2012    source แหล่งที่มา
comment
แต่ foo ไม่คงที่ แต่เป็นที่เก็บข้อมูลในเครื่อง...   -  person rodrigo    schedule 13.11.2012
comment
@rodrigo ฉันคิดว่าเวกเตอร์จะทำสำเนามันเหรอ?   -  person gsingh2011    schedule 13.11.2012
comment
และนี่คือข้อมูลอ้างอิงของฉันสำหรับความคิดเห็นนั้น: cplusplus.com/reference/stl/vector/ push_back   -  person gsingh2011    schedule 13.11.2012
comment
อืม ใช่ คุณพูดถูก คุณกำลังบันทึกตัวชี้ไปที่สำเนา vectored ไม่ใช่สำเนาต้นฉบับ ปัญหาคือคำตอบของ mythagel: ตัวชี้ใช้ไม่ได้   -  person rodrigo    schedule 13.11.2012


คำตอบ (3)


การเพิ่มรายการลงในเวกเตอร์จะทำให้ตัววนซ้ำก่อนหน้าทั้งหมดเป็นโมฆะ การเรียก push_back บนเวกเตอร์อาจทำให้พอยน์เตอร์ที่คุณได้รับก่อนหน้านี้ไม่ถูกต้อง หากเวกเตอร์จำเป็นต้องจัดสรรที่จัดเก็บข้อมูลภายในใหม่

หากคุณรู้ว่าคุณจะไม่ขยายเวกเตอร์อีกต่อไป สิ่งนี้ก็จะได้ผล:

for (int i = 0; i < 10; i++) {
  foos.push_back(Foo(i));
}

for (int i = 0; i < 10; i++) {
  pFoos.push_back(&foos[i]);
}

หรือตามที่ความเห็นโดยโรดริโก:

foos.reserve(10)

for (int i = 0; i < 10; i++) {
  Foo foo(i);
  foos.push_back(foo);
  pFoos.push_back(&foos.back());
}

for (int i = 0; i < 10; i++) {
  cout << foos[i].bar << endl;
  cout << pFoos[i]->bar << endl;
}
person mythagel    schedule 12.11.2012
comment
ไม่ใช่ทุก push_back จะทำให้เกิดการจัดสรรใหม่ เมื่อพื้นที่ที่จัดสรรหมดเท่านั้น - person jrok; 13.11.2012
comment
แทนที่จะทำให้ด้วยอาจทำและแก้ไขได้ เป็นที่น่าสังเกตว่าการโทร foos.reserve(10) จะป้องกัน UB - person rodrigo; 13.11.2012
comment
ขออภัย ใช่ ฉันกำลังทำให้ง่ายขึ้น - person mythagel; 13.11.2012
comment
ขอบคุณ มันสมเหตุสมผล ฉันไม่รู้เรื่องนี้เลย ฉันจะลองใช้รหัสของคุณแล้วยอมรับหากใช้งานได้ - person gsingh2011; 13.11.2012
comment
โซลูชันทั้งสองใช้งานได้! ขอบคุณเพื่อน. ฉันจะยอมรับใน 3 นาทีเมื่อ SO ให้ฉัน - person gsingh2011; 13.11.2012

ฉันเดาว่านี่ไม่ใช่วิธีการเขียนโปรแกรมที่ดี เวกเตอร์มีหน้าที่จัดเก็บวัตถุและอาจทำให้หน่วยความจำ REALLOC ได้รับหน่วยความจำที่ใหญ่ขึ้น ... ดังนั้นตัวชี้ของคุณจึงใช้ไม่ได้อีกต่อไป ...

person Roozbeh Zabihollahi    schedule 12.11.2012

vector::push_back สามารถย้ายองค์ประกอบได้ ซึ่งเป็นสาเหตุที่ทำให้ที่อยู่ไม่ถูกต้อง คุณสามารถโหลดหน่วยความจำสำหรับเวกเตอร์ให้เป็นขนาดสุดท้ายล่วงหน้าได้โดยการเรียก reserve ก่อนที่คุณจะเริ่มดันสิ่งต่าง ๆ เข้าไปในเวกเตอร์ หรือคุณสามารถรอจนกว่าคุณจะผลักสิ่งต่าง ๆ เสร็จก่อนที่จะนำที่อยู่ของมันไป

แต่คุณบอกว่าคุณ "ไม่สามารถใช้หน่วยความจำแบบไดนามิกได้" vector ใช้หน่วยความจำแบบไดนามิก

person Pete Becker    schedule 12.11.2012
comment
ฉันรู้ว่าเวกเตอร์ใช้หน่วยความจำแบบไดนามิก แต่ฉันหมายความว่าฉันไม่สามารถทำอะไรแบบ new Foo() ได้ แต่ขอบคุณ ฉันจะลองจองดู - person gsingh2011; 13.11.2012