ฉันจะทำอย่างไรกับวัตถุที่ถูกย้ายจาก?


138

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

ตัวอย่างเช่นใช้เทมเพลตฟังก์ชันswapตามที่กำหนดไว้ในไลบรารีมาตรฐาน:

template <typename T>
void swap(T& a, T& b)
{
    T c = std::move(a); // line 1
    a = std::move(b);   // line 2: assignment to moved-from object!
    b = std::move(c);   // line 3: assignment to moved-from object!
}

เห็นได้ชัดว่ามันจะต้องเป็นไปได้ที่จะกำหนดให้กับการย้ายจากวัตถุมิฉะนั้นบรรทัดที่ 2 และ 3 จะล้มเหลว แล้วฉันจะทำยังไงกับวัตถุที่ถูกย้าย? ฉันจะหารายละเอียดเหล่านี้ได้จากที่ไหน?

(อย่างไรก็ตามทำไมมันT c = std::move(a);แทนT c(std::move(a));ในบรรทัด 1)

คำตอบ:


53

วัตถุที่ถูกย้ายจากมีอยู่ในสถานะที่ไม่ระบุ แต่ถูกต้อง สิ่งนี้ชี้ให้เห็นว่าแม้ว่าวัตถุอาจไม่สามารถทำอะไรได้อีกมาก แต่ฟังก์ชันสมาชิกทั้งหมดยังคงต้องแสดงพฤติกรรมที่กำหนดไว้รวมถึงoperator=- และสมาชิกทั้งหมดในสถานะที่กำหนด - และยังต้องทำลาย มาตรฐานไม่ได้ให้คำจำกัดความที่เฉพาะเจาะจงเพราะมันจะไม่ซ้ำกันสำหรับแต่ละ UDT แต่คุณอาจจะสามารถค้นหาข้อมูลจำเพาะสำหรับประเภทมาตรฐาน บางอย่างเช่นภาชนะบรรจุค่อนข้างชัดเจน - พวกเขาเพียงแค่ย้ายเนื้อหาไปรอบ ๆ และภาชนะเปล่าเป็นสถานะที่ถูกต้องที่กำหนดไว้อย่างดี Primitives ไม่แก้ไขวัตถุที่ย้ายจาก

หมายเหตุด้านข้าง: ฉันเชื่อว่าเป็นไปได้T c = std::move(a)ว่าหากตัวสร้างการย้าย (หรือคัดลอกตัวสร้างหากไม่มีการย้าย) ให้ชัดเจนฟังก์ชั่นจะล้มเหลว


26
ไม่ได้ทุกการทำงานของฟังก์ชั่นสมาชิกจะจัดแสดงที่กำหนดไว้ เฉพาะผู้ที่ไม่มีเงื่อนไข ตัวอย่างเช่นคุณอาจไม่ต้องการที่จะย้ายจากpop_back แต่แน่นอนคุณจะพบว่าหากมันเป็นvector empty()
Howard Hinnant

6
@Howard Hinnant: pop_backจากความว่างเปล่าvectorมีพฤติกรรมที่ไม่ได้กำหนดต่อไปจากหน่วยความจำดังนั้นฉันค่อนข้างแน่ใจว่าpop_backจากเวกเตอร์ที่ถูกย้ายซึ่งแสดงพฤติกรรมที่ไม่ได้กำหนดนั้นสอดคล้องกัน
ลูกสุนัข

12
เรากำลังพูดถึงวัตถุที่ถูกย้าย วัตถุที่ไม่รู้จักจะอยู่ในสถานะว่างเปล่า วัตถุที่ถูกย้ายจากมีสถานะที่ไม่ระบุ (เว้นแต่จะระบุไว้เป็นอย่างอื่น) [lib.types.movedfrom]
Howard Hinnant

5
@Howard ไม่ได้ระบุ แต่ใช้ได้ดังนั้นpop_backยังคงมีพฤติกรรมเหมือนในเวกเตอร์ที่ถูกต้องใด ๆ (อาจเป็นแม้แต่เวกเตอร์ที่ว่างเปล่า)
Christian Rau

1
สิ่งที่ไม่ระบุและถูกต้องหมายถึงอะไรในบริบทนี้
Ankur S

114

17.6.5.15 [lib.types.movedfrom]

วัตถุประเภทที่กำหนดในไลบรารีมาตรฐาน C ++ อาจถูกย้ายจาก (12.8) การดำเนินการย้ายอาจมีการระบุไว้อย่างชัดเจนหรือสร้างขึ้นโดยนัย วัตถุที่ย้ายจากนั้นจะต้องอยู่ในสถานะที่ถูกต้อง แต่ไม่ได้ระบุเว้นแต่มีการระบุไว้เป็นอย่างอื่น

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

ตัวอย่างของการดำเนินการที่โดยทั่วไปไม่มีเงื่อนไข:

  • การทำลาย
  • การมอบหมาย
  • ผู้สังเกตการณ์ const เช่นget, empty,size

ตัวอย่างของการดำเนินการที่โดยทั่วไปมีเงื่อนไขเบื้องต้น:

  • dereference
  • pop_back

คำตอบนี้ปรากฏในรูปแบบวิดีโอที่นี่แล้ว: http://www.youtube.com/watch?v=vLinb2fgkHk&t=47m10s


1
แต่ฉันสามารถตรวจสอบเงื่อนไขเบื้องต้นได้เหมือนกับวัตถุอื่น ๆ ใช่ไหม
fredoverflow

6
@FredOverflow ตราบใดที่การตรวจสอบเหล่านี้ไม่มีเงื่อนไขแน่นอน
Christian Rau

1
@Chris: แต่วิธีการที่แตกต่างจากปกติไม่ใช่วัตถุย้าย?
fredoverflow

2
อาจเป็นคำถามที่แยกต่างหาก แต่นั่นหมายความว่า: ถ้าฉันมีสายอักขระchar* buffer;และint length;สมาชิกดังนั้นตัวสร้าง / การมอบหมายการย้ายของฉันต้องสลับ (หรือตั้งค่า) ค่าของทั้งสองหรือไม่ หรือมันจะตกลงถ้าความยาวไม่ได้ระบุ (หมายความว่าemptyและsizeส่งกลับค่าความหมาย)?
ลุง

3
@ 6502: คุณไม่สมเหตุสมผล คลาส C ++ 03 ไม่ได้ "ละเมิดมาตรฐาน C ++ 0x" เนื่องจาก ctor การย้ายหากสร้างขึ้นจะเป็นการละเมิดมาตรฐาน และรหัส C ++ 03 จะไม่ย้ายคลาสนั้นดังนั้นจึงไม่มีเหตุผลที่จะสร้าง ctor ย้าย
MSalters
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.