การจัดสรรหน่วยความจำแบบไดนามิกและการจัดการหน่วยความจำ


17

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

ฉันควรสร้างพูลหน่วยความจำสำหรับการจัดสรรแบบไดนามิกหรือไม่จำเป็นต้องกังวลกับสิ่งนี้? เกิดอะไรขึ้นถ้าแพลตฟอร์มเป้าหมายเป็นอุปกรณ์เคลื่อนที่

จำเป็นต้องมีผู้จัดการหน่วยความจำในเกมมือถือไหม? ขอขอบคุณ.

ภาษาที่ใช้: C ++; ขณะนี้ได้รับการพัฒนาภายใต้ Windows แต่มีแผนที่จะให้บริการในภายหลัง


ภาษาไหน?
Kylotan

@Kylotan: ภาษาที่ใช้: C ++ ได้รับการพัฒนาในปัจจุบันภายใต้ Windows แต่มีแผนที่จะย้ายในภายหลัง
Bunkai.Satori

คำตอบ:


23

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

นั่นขึ้นอยู่กับสิ่งที่คุณหมายถึงโดย "ถูกต้อง" หากคุณใช้คำนี้อย่างแท้จริง (และไม่สนใจแนวคิดใด ๆ ของความถูกต้องของการออกแบบโดยนัย) ใช่แล้วมันเป็นที่ยอมรับอย่างสมบูรณ์ โปรแกรมของคุณจะรวบรวมและทำงานได้ดี

มันอาจทำงานได้ดีที่สุด แต่ก็ยังทำงานได้ดีพอที่จะเป็นเกมที่สนุก

ฉันควรสร้างพูลหน่วยความจำสำหรับการจัดสรรแบบไดนามิกหรือไม่จำเป็นต้องกังวลกับสิ่งนี้? เกิดอะไรขึ้นถ้าแพลตฟอร์มเป้าหมายเป็นอุปกรณ์เคลื่อนที่

ดูรายละเอียดและ ใน C ++ ตัวอย่างเช่นการจัดสรรแบบไดนามิกบนฮีปมักเป็นการดำเนินการ "ช้า" (ซึ่งเกี่ยวข้องกับการเดินผ่านฮีปเพื่อค้นหาบล็อกที่มีขนาดเหมาะสม) ใน C # มักจะเป็นการดำเนินการที่รวดเร็วมากเนื่องจากเกี่ยวข้องกับการเพิ่มขึ้นเล็กน้อย การใช้งานภาษาที่แตกต่างกันมีคุณสมบัติด้านประสิทธิภาพที่แตกต่างกันเกี่ยวกับการจัดสรรหน่วยความจำการแตกแฟรกเมนต์เมื่อเผยแพร่

การใช้ระบบการรวมหน่วยความจำสามารถนำมาซึ่งผลการดำเนินงานที่แน่นอนและเนื่องจากระบบโทรศัพท์มือถือมักจะมีกำลังต่ำเมื่อเทียบกับระบบเดสก์ท็อปคุณอาจเห็นการเพิ่มขึ้นของแพลตฟอร์มมือถือมากกว่าที่คุณทำบนเดสก์ทอป แต่อีกครั้งคุณจะต้องทำการโพรไฟล์และดูว่า - ในปัจจุบันเกมของคุณช้า แต่การจัดสรร / การปล่อยหน่วยความจำไม่แสดงใน profiler ในฐานะฮอตสปอตการใช้โครงสร้างพื้นฐานเพื่อเพิ่มประสิทธิภาพการจัดสรรหน่วยความจำและการเข้าถึง คุณไม่ได้รับเงินมากสำหรับเจ้าชู้ของคุณ

จำเป็นต้องมีผู้จัดการหน่วยความจำในเกมมือถือไหม? ขอขอบคุณ.

อีกครั้งโปรไฟล์และดู เกมของคุณทำงานได้ดีหรือไม่? จากนั้นคุณอาจไม่ต้องกังวล

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

โดยเฉพาะอย่างยิ่งในตัวอย่างดั้งเดิมของคุณคุณอ้างถึง "กระสุน" ซึ่งมักจะเป็นสิ่งที่สร้างและทำลายบ่อยครั้ง - เพราะเกมหลายเกมเกี่ยวข้องกับกระสุนจำนวนมากและกระสุนเคลื่อนที่เร็วและถึงจุดสิ้นสุดของชีวิตอย่างรวดเร็ว (และบ่อยครั้ง รุนแรง!) ดังนั้นการใช้ตัวจัดสรรพูลสำหรับพวกเขาและวัตถุอย่างพวกมัน (เช่นอนุภาคในระบบอนุภาค) มักจะส่งผลให้ได้รับประสิทธิภาพและน่าจะเป็นที่แรกที่เริ่มมองหาโดยใช้การจัดสรรพูล

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

ตัวอย่างเช่นหากคุณพิจารณาตัวจัดการหน่วยความจำว่าเป็นสิ่งที่เพิ่งตัดการโทรไปที่ใหม่ / ลบ / ฟรี / malloc / อะไรก็ตามและให้การวินิจฉัยเกี่ยวกับจำนวนหน่วยความจำที่คุณจัดสรรสิ่งที่คุณรั่วไหลและอื่น ๆ - ที่เป็นประโยชน์ เครื่องมือสำหรับเกมขณะที่มันกำลังพัฒนาเพื่อช่วยให้คุณแก้จุดบกพร่องและปรับขนาดพูลหน่วยความจำที่เหมาะสมและอื่น ๆ


ตกลง รหัสในวิธีที่ช่วยให้คุณสามารถเปลี่ยนแปลงสิ่งต่าง ๆ ในภายหลัง หากมีข้อสงสัยให้อ้างอิงหรือโปรไฟล์
axel22

@ Josh: +1 สำหรับคำตอบที่ดี สิ่งที่ฉันอาจจะต้องมีคือการรวมกันของการจัดสรรแบบไดนามิกการจัดสรรแบบคงที่และพูลหน่วยความจำ อย่างไรก็ตามประสิทธิภาพของเกมจะแนะนำฉันในการผสมผสานที่เหมาะสมของทั้งสาม นี่คือผู้สมัครที่ชัดเจนสำหรับคำตอบที่ยอมรับสำหรับคำถามของฉัน อย่างไรก็ตามฉันอยากจะเปิดคำถามซักครู่เพื่อดูว่าคนอื่นจะช่วยอะไร
Bunkai.Satori

+1 ความประณีตที่ยอดเยี่ยม คำตอบของคำถามเกี่ยวกับประสิทธิภาพเกือบทุกคำถามคือ "โปรไฟล์และดู" เสมอ ฮาร์ดแวร์นั้นซับซ้อนเกินไปในทุกวันนี้เพื่อให้เหตุผลเกี่ยวกับประสิทธิภาพจากหลักการแรก คุณต้องการข้อมูล
munificent

@Munificent: ขอบคุณสำหรับความคิดเห็นของคุณ ดังนั้นเป้าหมายคือการทำให้เกมทำงานและมีความมั่นคง ไม่จำเป็นต้องกังวลเกี่ยวกับประสิทธิภาพมากเกินไปในช่วงกลางของการพัฒนา ทุกอย่างสามารถและจะได้รับการแก้ไขหลังจากเกมเสร็จสิ้น
Bunkai.Satori

ฉันคิดว่านี่เป็นตัวแทนที่ไม่ยุติธรรมของการจัดสรรเวลาของ C # - เช่นการจัดสรร C # ทุกครั้งยังรวมถึงการซิงค์บล็อกการจัดสรรวัตถุ ฯลฯ นอกจากนี้ฮีปใน C ++ ต้องการการแก้ไขเมื่อการจัดสรรและการปล่อยในขณะที่ C # ต้องมีการรวบรวม .
DeadMG

7

ฉันไม่ต้องเพิ่มคำตอบที่ยอดเยี่ยมของ Josh มากนัก แต่ฉันจะแสดงความคิดเห็นเกี่ยวกับเรื่องนี้:

ฉันควรสร้างพูลหน่วยความจำสำหรับการจัดสรรแบบไดนามิกหรือไม่จำเป็นต้องกังวลกับสิ่งนี้?

มีกราวด์กลางระหว่างพูลหน่วยความจำและการเรียกnewใช้การจัดสรรแต่ละครั้ง ตัวอย่างเช่นคุณสามารถจัดสรรจำนวนชุดของวัตถุในอาร์เรย์จากนั้นตั้งค่าสถานะในพวกเขาเพื่อ 'ทำลาย' พวกเขาในภายหลัง เมื่อคุณต้องการจัดสรรเพิ่มเติมคุณสามารถเขียนทับสิ่งเหล่านั้นด้วยชุดธงที่ทำลายได้ สิ่งนี้เป็นประเภทที่ซับซ้อนกว่าการใช้เล็กน้อยเพียงเล็กน้อยใหม่ / ลบ (เช่นคุณจะมี 2 ฟังก์ชั่นใหม่สำหรับวัตถุประสงค์นั้น) แต่เป็นเรื่องง่ายที่จะเขียนและสามารถให้ผลประโยชน์ที่ยิ่งใหญ่


+1 สำหรับการเพิ่มที่ดี ใช่คุณถูกต้องซึ่งเป็นวิธีที่ดีในการจัดการองค์ประกอบเกมที่ง่ายขึ้นเช่น: กระสุนอนุภาคผลกระทบ โดยเฉพาะอย่างยิ่งสำหรับผู้ที่ไม่จำเป็นต้องจัดสรรหน่วยความจำแบบไดนามิก
Bunkai.Satori

3

มันถูกต้องสมบูรณ์ในการจัดสรรหน่วยความจำสำหรับวัตถุทั้งหมดรวมถึงปืนนัด (กระสุน) แบบไดนามิกผ่านการเริ่มต้นใหม่ ()?

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

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


+1 สำหรับคำตอบที่ดี ดังนั้นโดยทั่วไปแนวทางที่ถูกต้องคือ: ในการเริ่มต้นของการพัฒนาเพื่อวางแผนว่าวัตถุใดที่สามารถจัดสรรแบบคงที่ ในระหว่างการพัฒนาการจัดสรรวัตถุเหล่านั้นแบบไดนามิกเท่านั้นที่จะต้องมีการจัดสรรแบบไดนามิก ในตอนท้ายไปยังโปรไฟล์และปรับปัญหาประสิทธิภาพการจัดสรรหน่วยความจำ
Bunkai.Satori

0

ชนิดของ echoing ข้อเสนอแนะของ Kylotan แต่ฉันอยากจะแนะนำให้แก้ปัญหานี้ในระดับโครงสร้างข้อมูลเมื่อเป็นไปได้ไม่ใช่ระดับตัวจัดสรรที่ต่ำกว่าหากคุณสามารถช่วยได้

นี่คือตัวอย่างง่ายๆของวิธีที่คุณสามารถหลีกเลี่ยงการจัดสรรและปล่อยFoosซ้ำ ๆ โดยใช้อาร์เรย์ที่มีรูพร้อมองค์ประกอบที่เชื่อมโยงเข้าด้วยกัน (การแก้ปัญหานี้ในระดับ "คอนเทนเนอร์" แทนที่จะเป็นระดับ "ตัวจัดสรร"):

struct FooNode
{
    explicit FooNode(const Foo& ielement): element(ielement), next(-1) {}

    // Stores a 'Foo'.
    Foo element;

    // Points to the next foo available; either the
    // next used foo or the next deleted foo. Can
    // use SoA and hoist this out if Foo doesn't 
    // have 32-bit alignment.
    int next;
};

struct Foos
{
    // Stores all the Foo nodes.
    vector<FooNode> nodes;

    // Points to the first used node.
    int first_node;

    // Points to the first free node.
    int free_node;

    Foos(): first_node(-1), free_node(-1)
    {
    }

    const FooNode& operator[](int n) const
    {
         return data[n];
    }

    void insert(const Foo& element)
    {
         int index = free_node;
         if (index != -1)
         {
              // If there's a free node available,
              // pop it from the free list, overwrite it,
              // and push it to the used list.
              free_node = data[index].next;
              data[index].next = first_node;
              data[index].element = element;
              first_node = index;
         }
         else
         {
              // If there's no free node available, add a 
              // new node and push it to the used list.
              FooNode new_node(element);
              new_node.next = first_node;
              first_node = data.size() - 1;
              data.push_back(new_node);
         }
    }

    void erase(int n)
    {
         // If the node being removed is the first used
         // node, pop it from the used list.
         if (first_node == n)
              first_node = data[n].next;

         // Push the node to the free list.
         data[n].next = free_node;
         free_node = n;
    }
};

บางสิ่งที่มีผลกระทบนี้: รายการดัชนีที่เชื่อมโยงเดี่ยวพร้อมรายการฟรี ลิงก์ดัชนีช่วยให้คุณสามารถข้ามองค์ประกอบที่ถูกลบลบองค์ประกอบในเวลาคงที่และยังเรียกคืน / นำมาใช้ซ้ำ / เขียนทับองค์ประกอบฟรีพร้อมการแทรกเวลาคงที่ ในการทำซ้ำโครงสร้างคุณทำสิ่งนี้:

for (int index = foos.first_node; index != -1; index = foos[index].next)
    // do something with foos[index]

ป้อนคำอธิบายรูปภาพที่นี่

และคุณสามารถวางโครงสร้างข้อมูลแบบ "ลิงก์อาร์เรย์ของหลุม" ข้างต้นโดยใช้เทมเพลตการวางตำแหน่งใหม่และการเรียกใช้ dtor แบบแมนนวลเพื่อหลีกเลี่ยงข้อกำหนดสำหรับการมอบหมายการคัดลอกทำให้มันเรียกใช้ destructors เมื่อองค์ประกอบถูกเอาออก เลือกที่จะรักษาตัวอย่าง C-like ให้ชัดเจนยิ่งขึ้นเพื่อแสดงแนวคิดและเพราะฉันขี้เกียจมาก

ที่กล่าวว่าโครงสร้างนี้มีแนวโน้มที่จะลดลงในพื้นที่เชิงพื้นที่หลังจากที่คุณลบและแทรกสิ่งที่มากไป / จากตรงกลาง เมื่อถึงจุดนั้นnextลิงก์อาจทำให้คุณเดินไปมาตามเวกเตอร์ได้การโหลดข้อมูลที่เคยถูกขับไล่ออกจากแคชในการเดินทางตามลำดับเดียวกัน (นี่เป็นสิ่งที่หลีกเลี่ยงไม่ได้กับโครงสร้างข้อมูลหรือตัวจัดสรรที่อนุญาตให้มีการลบเวลาคงที่โดยไม่ต้องสับองค์ประกอบ ช่องว่างจากตรงกลางที่มีการแทรกเวลาคงที่และไม่ต้องใช้อะไรเช่นชุดบิตขนานหรือremovedธง) ในการกู้คืนแคชที่เป็นมิตรคุณสามารถใช้วิธีคัดลอก ctor และสลับเช่นนี้:

Foos(const Foos& other)
{
    for (int index = other.first_node; index != -1; index = other[index].next)
        insert(foos[index].element);
}

void Foos::swap(Foos& other)
{
     nodes.swap(other.nodes):
     std::swap(first_node, other.first_node);
     std::swap(free_node, other.free_node);
}

// ... then just copy and swap:
Foos(foos).swap(foos);

ตอนนี้เวอร์ชันใหม่ใช้งานแคชได้อีกครั้งเพื่อทำการสำรวจ อีกวิธีคือจัดเก็บรายการดัชนีแยกต่างหากลงในโครงสร้างและจัดเรียงดัชนีเป็นระยะ อีกประการหนึ่งคือการใช้บิตเซ็ตเพื่อระบุว่าจะใช้ดัชนีใด ซึ่งจะทำให้คุณผ่านบิตเซ็ตตามลำดับ (เพื่อทำสิ่งนี้ได้อย่างมีประสิทธิภาพตรวจสอบ 64- บิตในแต่ละครั้งเช่นใช้ FFS / FFZ) บิตเซ็ตนั้นมีประสิทธิภาพมากที่สุดและไม่รบกวนซึ่งต้องการเพียงบิตบิตต่อองค์ประกอบเพื่อระบุว่ามีการใช้งานใดและจะถูกลบออกแทนที่จะใช้nextดัชนี32- บิตแต่ใช้เวลามากในการเขียนดี จะเร็วสำหรับการสำรวจเส้นทางถ้าคุณกำลังตรวจสอบทีละบิต - คุณต้อง FFS / FFZ เพื่อค้นหาบิตที่ตั้งค่าหรือไม่ตั้งค่าทันทีในหมู่ 32+ บิตในแต่ละครั้งเพื่อกำหนดช่วงของดัชนีที่ถูกครอบครองอย่างรวดเร็ว)

โซลูชันที่เชื่อมโยงนี้โดยทั่วไปแล้วเป็นวิธีที่ง่ายที่สุดในการติดตั้งและไม่ล่วงล้ำ (ไม่จำเป็นต้องแก้ไขFooเพื่อเก็บremovedค่าสถานะบางอย่าง) ซึ่งเป็นประโยชน์ถ้าคุณต้องการทำให้คอนเทนเนอร์นี้ทำงานกับชนิดข้อมูลใด ๆ หากคุณไม่สนใจว่า 32 บิต ค่าใช้จ่ายต่อองค์ประกอบ

ฉันควรสร้างพูลหน่วยความจำสำหรับการจัดสรรแบบไดนามิกหรือไม่จำเป็นต้องกังวลกับสิ่งนี้? เกิดอะไรขึ้นถ้าแพลตฟอร์มเป้าหมายเป็นอุปกรณ์เคลื่อนที่

จำเป็นต้องมีคำที่แข็งแกร่งและฉันลำเอียงทำงานในพื้นที่ที่มีประสิทธิภาพที่สำคัญมากเช่น raytracing การประมวลผลภาพการจำลองอนุภาคและการประมวลผลตาข่าย แต่มันค่อนข้างแพงมากที่จะจัดสรรและปล่อยวัตถุเล็ก ๆ ที่ใช้สำหรับการประมวลผลที่เบามากเช่นกระสุน และอนุภาคทีละตัวเทียบกับตัวจัดสรรหน่วยความจำอเนกประสงค์ขนาดวัตถุประสงค์ ระบุว่าคุณควรจะสามารถสรุปโครงสร้างข้อมูลข้างต้นในหนึ่งหรือสองวันเพื่อเก็บสิ่งที่คุณต้องการฉันคิดว่ามันเป็นการแลกเปลี่ยนที่คุ้มค่าที่จะกำจัดค่าใช้จ่ายในการจัดสรรฮีป / การจัดสรรคืนทันทีจากการจ่ายสำหรับทุกสิ่งเล็ก ๆ ด้านบนของการลดต้นทุนการจัดสรร / การจัดสรรคืนคุณจะได้รับตำแหน่งที่ดีขึ้นของการอ้างอิงภายในผลลัพธ์

เป็นสิ่งที่จอชกล่าวถึงเกี่ยวกับ GC ผมยังไม่ได้ศึกษา C # 's การดำเนินงาน GC ค่อนข้างเป็นอย่างใกล้ชิดเป็น Java แต่ allocators GC มักจะมีการจัดสรรเบื้องต้นมันเร็วมากเพราะใช้ตัวจัดสรรแบบลำดับซึ่งไม่สามารถเพิ่มหน่วยความจำจากตรงกลางได้ (เกือบเหมือนกับสแต็กคุณไม่สามารถลบสิ่งที่อยู่ตรงกลางได้) จากนั้นจ่ายสำหรับค่าใช้จ่ายแพงจริง ๆ แล้วอนุญาตให้ลบวัตถุแต่ละรายการในเธรดแยกต่างหากโดยการคัดลอกหน่วยความจำและล้างหน่วยความจำที่จัดสรรไว้ก่อนหน้าทั้งหมด (เช่นทำลายทั้งกองในคราวเดียวในขณะที่คัดลอกข้อมูลไปยังโครงสร้างที่เชื่อมโยง) แต่เนื่องจากมันทำในเธรดแยกต่างหากจึงไม่จำเป็นต้องทำให้เธรดแอปพลิเคชันของคุณค้างอยู่บ่อยนัก อย่างไรก็ตามนั่นมีค่าใช้จ่ายแอบแฝงที่สำคัญมากของระดับทางอ้อมเพิ่มเติมและการสูญเสียทั่วไปของ LOR หลังจากรอบ GC เริ่มต้น เป็นอีกกลยุทธ์หนึ่งที่เร่งการจัดสรรให้เร็วขึ้น - ทำให้ราคาถูกลงในการเรียกเธรด เพื่อที่คุณจะต้องมีการอ้อมสองระดับเพื่ออ้างอิงวัตถุของคุณแทนที่จะเป็นหนึ่งเนื่องจากพวกเขาจะได้รับการสับในหน่วยความจำระหว่างเวลาที่คุณจัดสรรครั้งแรกและหลังจากรอบแรก

กลยุทธ์อื่นในหลอดเลือดดำที่คล้ายกันซึ่งง่ายกว่าที่จะใช้ใน C ++ เพียงแค่ไม่ต้องกังวลกับการปล่อยวัตถุของคุณในเธรดหลักของคุณ เพียงแค่เพิ่มและเพิ่มและเพิ่มไปยังจุดสิ้นสุดของโครงสร้างข้อมูลซึ่งไม่อนุญาตให้นำสิ่งต่าง ๆ ออกจากกลาง อย่างไรก็ตามทำเครื่องหมายสิ่งเหล่านั้นที่จำเป็นต้องลบออก จากนั้นเธรดที่แยกจากกันสามารถดูแลงานที่มีราคาแพงในการสร้างโครงสร้างข้อมูลใหม่โดยไม่ต้องใช้องค์ประกอบที่ถูกลบออกและจากนั้นแลกเปลี่ยนอะตอมมิกใหม่กับอะตอมเก่าเช่นอะตอมของต้นทุนการจัดสรรและการปล่อยองค์ประกอบจำนวนมากสามารถส่งผ่านไปยัง แยกเธรดถ้าคุณสามารถทำการสันนิษฐานได้ว่าการขอลบองค์ประกอบนั้นไม่จำเป็นต้องได้รับความพึงพอใจทันที ที่ไม่เพียง แต่ทำให้การถูกกว่าเท่าที่หัวข้อของคุณมีความกังวล แต่ทำให้การจัดสรรถูกกว่า เนื่องจากคุณสามารถใช้โครงสร้างข้อมูลที่เรียบง่ายกว่าและไม่น่าไว้วางใจซึ่งไม่ต้องจัดการกับกรณีการลบจากกลาง มันเหมือนภาชนะที่ต้องการเพียงpush_backฟังก์ชั่นสำหรับการแทรก, clearฟังก์ชั่นเพื่อลบองค์ประกอบทั้งหมด, และswapเพื่อแลกเปลี่ยนเนื้อหากับภาชนะขนาดกะทัดรัดใหม่ไม่รวมองค์ประกอบที่ถูกลบออก; มันเท่าที่กลายพันธุ์ไป

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.