0Pricing
Swift Academy · บทเรียน

ตัวชี้บัฟเฟอร์ที่ไม่ปลอดภัย

ประมวลผลหน่วยความจำที่ต่อเนื่องกันอย่างมีประสิทธิภาพ

ตัวชี้บัฟเฟอร์ที่ไม่ปลอดภัย เป็นบทเรียน Swift Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Swift Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน

ตัวชี้บัฟเฟอร์คืออะไร

ตัวชี้ที่ระบุชนิดจะเข้าถึงองค์ประกอบได้ครั้งละหนึ่งรายการ UnsafeBufferPointer<T> จะห่อหุ้ม ตัวชี้เริ่มต้นพร้อมจำนวน เพื่อมอบมุมมองที่มีขอบเขตเหนือบล็อกหน่วยความจำที่ต่อเนื่องกัน ซึ่งสอดคล้องกับ Collection

นั่นหมายความว่าคุณสามารถวนซ้ำ เข้าถึงด้วยดัชนี ใช้ map และ reduce ได้ ซึ่งก็คือ API ของคอลเลกชันที่คุ้นเคยทั้งหมดบนหน่วยความจำดิบ

// A buffer pointer = base address + element count
// UnsafeBufferPointer<Int>(start: ptr, count: 5)

บัฟเฟอร์แบบอ่านอย่างเดียวกับแบบเปลี่ยนแปลงได้

เช่นเดียวกับตัวชี้เดี่ยว บัฟเฟอร์มีอยู่สองรูปแบบ ได้แก่ UnsafeBufferPointer<T> สำหรับการวนซ้ำแบบอ่านอย่างเดียว และ UnsafeMutableBufferPointer<T> เมื่อต้องการกำหนดค่าให้องค์ประกอบด้วย

let p = UnsafeMutablePointer<Int>.allocate(capacity: 4)
p.initialize(repeating: 0, count: 4)
let buf = UnsafeMutableBufferPointer(start: p, count: 4)
buf[0] = 11
print(buf[0]) // 11

การวนซ้ำเหมือนคอลเลกชัน

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

let buf = UnsafeMutableBufferPointer<Int>.allocate(capacity: 3)
_ = buf.initialize(from: [10, 20, 30])
for value in buf { print(value) } // 10, 20, 30

ใช้อัลกอริทึมของคอลเลกชันได้ทันที

map, filter, reduce, enumerated และ indices ทั้งหมดทำงานกับตัวชี้บัฟเฟอร์ได้ ทำให้คุณประมวลผลหน่วยความจำดิบด้วยโค้ดระดับสูงได้ โดยไม่ต้องจัดสรรหน่วยความจำ

let buf = UnsafeMutableBufferPointer<Int>.allocate(capacity: 4)
_ = buf.initialize(from: [1, 2, 3, 4])
let total = buf.reduce(0, +)   // 10
let evens = buf.filter { $0 % 2 == 0 } // [2, 4]
print(total, evens)

การจัดสรรบัฟเฟอร์ที่เปลี่ยนแปลงได้

UnsafeMutableBufferPointer<T>.allocate(capacity:) จะจองบล็อกหน่วยความจำและส่งคืนบัฟเฟอร์ให้ในขั้นตอนเดียว แต่คุณยังต้อง initialize ก่อนอ่าน และต้อง deallocate เมื่อใช้งานเสร็จ

let buf = UnsafeMutableBufferPointer<Int>.allocate(capacity: 5)
buf.initialize(repeating: 0)
defer {
    buf.deinitialize()
    buf.deallocate()
}

ไม่มีการตรวจสอบขอบเขตที่ปลายบัฟเฟอร์

การเข้าถึงด้วยดัชนีภายใน 0..<count นั้นทำได้ แต่บัฟเฟอร์ไม่อาจรู้ได้ว่า จำนวนที่คุณระบุ ถูกต้องหรือไม่ หากคุณสร้างบัฟเฟอร์ด้วยจำนวนที่มากกว่าการจัดสรรจริง การอ่านจะเลยจุดสิ้นสุดเข้าไปในหน่วยความจำที่ไม่มีการกำหนดความหมาย

ให้คำนวณจำนวนจากการจัดสรรเดียวกับที่คุณสร้างเสมอ

let p = UnsafeMutablePointer<Int>.allocate(capacity: 3)
p.initialize(repeating: 0, count: 3)
// CORRECT: count matches capacity
let good = UnsafeBufferPointer(start: p, count: 3)
// WRONG: count: 10 would read past the block
print(good.count)

บัฟเฟอร์ว่าง

บัฟเฟอร์ที่มี count: 0 ถือว่าใช้งานได้และอาจมีที่อยู่เริ่มต้นเป็น nil ให้ตรวจสอบ isEmpty เสมอ หรือปล่อยให้ลูปไม่ทำงานแทนการบังคับแกะค่า baseAddress

let empty = UnsafeBufferPointer<Int>(start: nil, count: 0)
print(empty.isEmpty)       // true
print(empty.count)         // 0
for _ in empty { print("never runs") }

withUnsafeBufferPointer บนอาร์เรย์

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

let numbers = [4, 8, 15, 16, 23]
let maxValue = numbers.withUnsafeBufferPointer { buf -> Int in
    var m = buf[0]
    for v in buf where v > m { m = v }
    return m
}
print(maxValue) // 23

การเปลี่ยนแปลงพื้นที่จัดเก็บของอาร์เรย์

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

var data = [1, 2, 3, 4]
data.withUnsafeMutableBufferPointer { buf in
    for i in buf.indices { buf[i] *= 10 }
}
print(data) // [10, 20, 30, 40]

baseAddress สำหรับ API ของ C

เมื่อเรียกฟังก์ชัน C ที่ต้องการตัวชี้พร้อมความยาว ให้ส่ง buffer.baseAddress และ buffer.count ที่อยู่เริ่มต้นจะเป็น nil เฉพาะเมื่อบัฟเฟอร์ว่าง ดังนั้นต้องจัดการกรณีนี้ด้วย

let bytes: [UInt8] = [0xDE, 0xAD, 0xBE, 0xEF]
bytes.withUnsafeBufferPointer { buf in
    if let base = buf.baseAddress {
        // c_function(base, buf.count)
        print("start:", base, "len:", buf.count)
    }
}

เมื่อใดควรใช้ตัวชี้บัฟเฟอร์

ใช้ตัวชี้บัฟเฟอร์เมื่อต้องการเข้าถึงพื้นที่หน่วยความจำแบบต่อเนื่อง ซึ่งมีชนิดข้อมูลปลอดภัยและมีรูปแบบเหมือนคอลเลกชัน เช่น การเชื่อมอาร์เรย์ C การแยกวิเคราะห์รูปแบบไบนารี หรือการลดค่าใช้จ่ายในลูปที่ทำงานบ่อย ๆ หากเป็นไปได้ ให้เลือกรูปแบบคลอเชอร์ with... แทนการจัดสรรหน่วยความจำด้วยตนเอง

// Counting set bits across a byte buffer
let data: [UInt8] = [0b1011, 0b0110, 0b1111]
let bits = data.withUnsafeBufferPointer { buf in
    buf.reduce(0) { $0 + $1.nonzeroBitCount }
}
print(bits) // 3 + 2 + 4 = 9

ตรวจสอบความเข้าใจ

ลองทบทวนว่าตัวชี้บัฟเฟอร์เพิ่มความสามารถอะไรจากตัวชี้เดี่ยว

สรุป

ตัวชี้บัฟเฟอร์จะห่อหุ้มพื้นที่หน่วยความจำที่ต่อเนื่องกันให้เป็นคอลเลกชันที่มีขอบเขต:

  • UnsafeBufferPointer / UnsafeMutableBufferPointer = ที่อยู่เริ่มต้น + จำนวน
  • คุณจะได้ map, filter, reduce และการวนซ้ำด้วย for บนหน่วยความจำดิบ
  • เลือกใช้ withUnsafeBufferPointer กับอาร์เรย์ เพื่อให้ Swift จัดการความถูกต้องและอายุการใช้งาน
  • ระบบจะเชื่อถือจำนวนที่ระบุ ดังนั้นให้คำนวณจากการจัดสรรจริง

คำถามที่พบบ่อย

บทเรียน “ตัวชี้บัฟเฟอร์ที่ไม่ปลอดภัย” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “ตัวชี้บัฟเฟอร์ที่ไม่ปลอดภัย” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Swift Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “ตัวชี้บัฟเฟอร์ที่ไม่ปลอดภัย”

ประมวลผลหน่วยความจำที่ต่อเนื่องกันอย่างมีประสิทธิภาพ คุณปฏิบัติ Swift Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Swift Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Swift Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “ตัวชี้บัฟเฟอร์ที่ไม่ปลอดภัย” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Swift Academy นี้ได้ไหม

ได้ บทเรียน Swift Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. MemoryLayout และการจัดแนว
  2. UnsafePointer และ UnsafeMutablePointer
  3. ตัวชี้บัฟเฟอร์ที่ไม่ปลอดภัย
  4. withUnsafeBytes และการทำงานร่วมกับ C
← กลับไปที่ Swift Academy