เหตุใด auto_ptr จึงเลิกใช้งาน


95

ฉันได้ยินมาว่าauto_ptrกำลังเลิกใช้งานใน C ++ 11 เหตุผลนี้คืออะไร?

นอกจากนี้ผมอยากจะทราบความแตกต่างระหว่างและauto_ptrshared_ptr


คำตอบ:


93

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

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


25
หมายเหตุเกี่ยวกับauto_ptrชื่อ: auto แนะนำอัตโนมัติเช่นเดียวกับในตัวแปรอัตโนมัติและอ้างถึงสิ่งหนึ่งที่auto_ptrทำ: ทำลายทรัพยากรที่มีการจัดการในตัวทำลาย (เมื่ออยู่นอกขอบเขต)
Vincenzo Pii

14
ข้อมูลเพิ่มเติม: นี่คือเหตุผลอย่างเป็นทางการสำหรับการเลิกใช้auto_ptr: open-std.org/jtc1/sc22/wg21/docs/papers/2005/…
Howard Hinnant

@HowardHinnant เอกสารที่น่าสนใจ! เป็นเรื่องแปลกในแง่ที่ถ้า std :: sort () มีความเชี่ยวชาญเฉพาะสำหรับ std :: unique_ptr เพื่อใช้ความหมายการย้ายตามต้องการ ฉันสงสัยว่าทำไม std :: sort () ไม่สามารถใช้เฉพาะสำหรับ std :: auto_ptr เพื่อแก้ไขปัญหาการคัดลอกที่กล่าวถึงในเอกสาร ขอบคุณล่วงหน้า.
Hei

2
@ เห่ย: std::sortไม่มีความเชี่ยวชาญสำหรับunique_ptr. แต่มีการระบุอีกครั้งว่าห้ามคัดลอก ดังนั้นauto_ptrจริงไม่sortทำงานร่วมกับโมเดิร์น แต่ C ++ 98/03 sortเป็นเพียงขั้นตอนวิธีการเช่นที่นี่: ใด ๆขั้นตอนวิธีการทั่วไป (STD จัดหรือผู้ใช้ที่เขียน) ที่สันนิษฐานว่าไวยากรณ์สำเนามีความหมายสำเนาอาจจะมีข้อผิดพลาดเวลาทำงานถ้าใช้กับauto_ptrเพราะauto_ptrเงียบย้ายด้วยไวยากรณ์การคัดลอก ปัญหาคือมากsortมีขนาดใหญ่กว่าเพียง
Howard Hinnant

36

ฉันพบว่าคำตอบที่มีอยู่นั้นยอดเยี่ยม แต่จาก PoV ของพอยน์เตอร์ IMO คำตอบที่ดีควรมีคำตอบจากมุมมองของผู้ใช้ / โปรแกรมเมอร์

สิ่งแรกก่อน (ตามที่ Jerry Coffin ชี้ในคำตอบของเขา)

  • auto_ptr สามารถแทนที่ด้วย shared_ptr หรือ unique_ptr ขึ้นอยู่กับสถานการณ์

shared_ptr: หากคุณกังวลเกี่ยวกับการปลดปล่อยทรัพยากร / หน่วยความจำและหากคุณมีมากกว่าหนึ่งฟังก์ชันที่สามารถใช้อ็อบเจ็กต์ AT-DIFFERENT ครั้งให้ไปที่ shared_ptr

ตามเวลาที่แตกต่างกันให้นึกถึงสถานการณ์ที่ object-ptr ถูกเก็บไว้ในโครงสร้างข้อมูลหลายรายการและเข้าถึงได้ในภายหลัง แน่นอนว่าหลายเธรดเป็นอีกตัวอย่างหนึ่ง

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

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

จากบรรทัดนี้ฉันจะอ้างถึง _ptr ที่ใช้ร่วมกัน / ไม่ซ้ำกันเป็นตัวชี้อัจฉริยะ (auto_ptr ยังเป็นตัวชี้อัจฉริยะ แต่เนื่องจากมีข้อบกพร่องในการออกแบบซึ่งกำลังเลิกใช้งานและซึ่งฉันคิดว่าฉันจะชี้ให้เห็นในบรรทัดถัดไปไม่ควรจัดกลุ่มด้วยตัวชี้อัจฉริยะ)

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

จากลิงค์: http://www.cplusplus.com/reference/memory/unique_ptr/operator=/

ประเภทของงานที่สนับสนุนโดย unqiue_ptr

  • ย้ายงาน (1)
  • กำหนดตัวชี้โมฆะ (2)
  • การกำหนดประเภท - นักแสดง (3)
  • คัดลอกงาน (ลบ!) (4)

จาก: http://www.cplusplus.com/reference/memory/auto_ptr/operator=/

ประเภทงานที่รองรับโดย auto_ptr

  • คัดลอกการมอบหมาย (4) ผู้ร้าย

ตอนนี้มาถึงเหตุผลว่าทำไมการกำหนดสำเนาถึงไม่ชอบฉันจึงมีทฤษฎีนี้:

  1. โปรแกรมเมอร์บางคนไม่ได้อ่านหนังสือหรือมาตรฐาน
  2. auto_ptr บนใบหน้าของมันสัญญาว่าคุณเป็นเจ้าของวัตถุ
  3. little- * (เล่นสำนวนเจตนา) ประโยคของ auto_ptr ซึ่งโปรแกรมเมอร์ทุกคนไม่ได้อ่านอนุญาตการกำหนด auto_ptr หนึ่งไปยังอีกอันหนึ่งและโอนความเป็นเจ้าของ
  4. การวิจัยพบว่าพฤติกรรมนี้มีไว้สำหรับ 3.1415926535% ของการใช้งานทั้งหมดและไม่ได้ตั้งใจในกรณีอื่น ๆ

พฤติกรรมที่ไม่ได้ตั้งใจเป็นสิ่งที่ไม่ชอบจริงๆและด้วยเหตุนี้จึงไม่ชอบสำหรับ auto_ptr

(สำหรับโปรแกรมเมอร์ 3.1415926536% ที่จงใจต้องการโอนความเป็นเจ้าของ C ++ 11 ให้ std :: move () ซึ่งทำให้ความตั้งใจของพวกเขาชัดเจนสำหรับนักศึกษาฝึกงานทุกคนที่กำลังจะอ่านและรักษารหัส)


1
เนื่องจากคุณไม่ต้องการให้auto_ptrค่าสองค่าชี้ไปที่วัตถุเดียวกัน (เนื่องจากพวกเขาไม่ได้ให้ความเป็นเจ้าของร่วมกันคนแรกที่ตายจะทิ้งอีกอย่างไว้ด้วยมรดกที่ร้ายแรงนี่เป็นเรื่องจริงสำหรับunique_ptrการใช้งาน) คุณช่วยแนะนำสิ่งที่ตั้งใจไว้ได้ไหมที่เหลือ 96.8584073465% ของการใช้งานทั้งหมด?
Marc van Leeuwen

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

@AjeetGanga ในวลีต่อไปนี้ "the little- * (เล่นสำนวนเจตนา)" คุณพูดว่า "เล่นสำนวนเจตนา" วลีนี้ใหม่สำหรับฉันและยังไงก็ตามฉันก็ใช้มันและได้รู้ว่ามีเรื่องตลกบางอย่างที่ตั้งใจทำที่นี่ เรื่องตลกที่นี่คืออะไร? แค่อยากรู้ว่า
VINOTH ENERGETIC

@AjeetGanga คุณพูดถึงเช่น 'the little- * (เล่นสำนวนเจตนา) ประโยคของ auto_ptr ซึ่งโปรแกรมเมอร์ทุกคนไม่ได้อ่านอนุญาตให้มอบหมาย auto_ptr หนึ่งไปยังอีกเครื่องหนึ่งและโอนความเป็นเจ้าของ' สมมติว่าฉันมี ptr อัตโนมัติสองตัวเป็น a และ b เป็นจำนวนเต็ม ฉันกำลังทำการมอบหมายเนื่องจากที่*a=*b;นี่มีเพียงค่า b เท่านั้นที่ถูกคัดลอกไปยังไฟล์. ฉันหวังว่าการเป็นเจ้าของทั้ง a และ b ยังคงอยู่กับคนเดิม ที่คุณกล่าวถึงเช่นการเป็นหนี้จะถูกโอน จะเป็นยังไง?
VINOTH ENERGETIC

@VINOTHENERGETIC Ajeet กำลังพูดถึงการกำหนดให้กับauto_ptrวัตถุนั้นเอง การกำหนดให้กับ / จากค่าที่ชี้ไปยังไม่มีผลกระทบหรือความเกี่ยวข้องกับความเป็นเจ้าของ ฉันหวังว่าคุณจะยังไม่ได้ใช้auto_ptr?
underscore_d

23

shared_ptrสามารถเก็บไว้ในภาชนะ auto_ptrลาด.

BTW unique_ptrเป็นการauto_ptrทดแทนโดยตรงโดยรวมคุณสมบัติที่ดีที่สุดของทั้งสองstd::auto_ptrและboost::scoped_ptr.


11

ยังต้องใช้เวลาอีกในการอธิบายความแตกต่าง ....

ตามหน้าที่แล้ว C ++ 11 std::unique_ptrคือ "คงที่" std::auto_ptr: ทั้งสองอย่างเหมาะสมเมื่อ - ณ เวลาใด ๆ ในระหว่างการดำเนินการ - ควรมีเจ้าของตัวชี้อัจฉริยะเพียงตัวเดียวสำหรับวัตถุที่ชี้ไปที่

ความแตกต่างที่สำคัญคือการสร้างสำเนาหรือการมอบหมายจากตัวชี้อัจฉริยะอื่นที่ยังไม่หมดอายุซึ่งแสดงไว้ใน=>บรรทัดด้านล่าง:

   std::auto_ptr<T> ap(...);
   std::auto_ptr<T> ap2(get_ap_to_T());   // take expiring ownership
=> std::auto_ptr<T> ap3(ap);  // take un-expiring ownership ala ap3(ap.release());
   ap->xyz;  // oops... can still try to use ap, expecting it to be non-NULL

   std::unique_ptr<T> up(...);
   std::unique_ptr<T> up2(get_up_to_T());   // take expiring ownership
=> std::unique_ptr<T> up3(up);  // COMPILE ERROR: can't take un-expiring ownership
=> std::unique_ptr<T> up4(std::move(up));  // EXPLICIT code allowed
=> std::unique_ptr<T> up4(up.release());   // EXPLICIT code allowed

ด้านบนap3"ขโมย" ความเป็นเจ้าของอย่างเงียบ ๆ*apปล่อยให้apตั้งค่าเป็น a nullptrและปัญหาก็คืออาจเกิดขึ้นได้ง่ายเกินไปโดยที่โปรแกรมเมอร์ไม่ได้คำนึงถึงความปลอดภัย

ตัวอย่างเช่นหาก a class/ structมีstd::auto_ptrสมาชิกการทำสำเนาอินสแตนซ์releaseตัวชี้จากอินสแตนซ์จะถูกคัดลอกนั่นคือความหมายที่แปลกและสับสนอย่างอันตรายเนื่องจากโดยปกติการคัดลอกบางสิ่งจะไม่แก้ไข เป็นเรื่องง่ายสำหรับผู้เขียนคลาส / โครงสร้างที่จะมองข้ามการเปิดตัวของตัวชี้เมื่อให้เหตุผลเกี่ยวกับค่าคงที่และสถานะและด้วยเหตุนี้จึงมีความพยายามที่จะหักค่าตัวชี้สมาร์ทโดยไม่ได้ตั้งใจในขณะที่เป็นโมฆะหรือเพียงแค่ไม่คาดว่าจะมีการเข้าถึง / เป็นเจ้าของข้อมูลที่ชี้ไป


auto_ptr เงียบ "ขโมย" ความเป็นเจ้าของ +1
camino

3

auto_ptr ไม่สามารถนำมาใช้ในภาชนะ STL เพราะมันมีตัวสร้างสำเนาที่ไม่ตรงตามความต้องการของภาชนะCopyConstructible unique_ptr ไม่ได้ใช้ตัวสร้างการคัดลอกดังนั้นคอนเทนเนอร์จึงใช้วิธีอื่น unique_ptr สามารถใช้ในคอนเทนเนอร์ได้และเร็วกว่าสำหรับอัลกอริทึม std มากกว่า shared_ptr

#include <iostream>
#include <type_traits>
#include <vector>
#include <memory>

using namespace std;

int main() {
  cout << boolalpha;
  cout << "is_copy_constructible:" << endl;
  cout << "auto_ptr: " << is_copy_constructible< auto_ptr<int> >::value << endl;
  cout << "unique_ptr: " << is_copy_constructible< unique_ptr<int> >::value << endl;
  cout << "shared_ptr: " << is_copy_constructible< shared_ptr<int> >::value << endl;

  vector<int> i_v;
  i_v.push_back(1);
  cout << "i_v=" << i_v[0] << endl;
  vector<int> i_v2=i_v;
  cout << "i_v2=" << i_v2[0] << endl;

  vector< unique_ptr<int> > u_v;
  u_v.push_back(unique_ptr<int>(new int(2)));
  cout << "u_v=" << *u_v[0] << endl;
  //vector< unique_ptr<int> > u_v2=u_v;  //will not compile, need is_copy_constructible == true
  vector< unique_ptr<int> > u_v2 =std::move(u_v);  // but can be moved
  cout << "u_v2=" << *u_v2[0] << " length u_v: " <<u_v.size() << endl;

  vector< shared_ptr<int> > s_v;
  shared_ptr<int> s(new int(3));
  s_v.push_back(s);
  cout << "s_v=" << *s_v[0] << endl;
  vector< shared_ptr<int> > s_v2=s_v;
  cout << "s_v2=" << *s_v2[0] << endl;

  vector< auto_ptr<int> > a_v;  //USAGE ERROR

  return 0;
}

>cxx test1.cpp -o test1
test1.cpp: In function âint main()â:
test1.cpp:33:11: warning: âauto_ptrâ is deprecated (declared at /apps/hermes/sw/gcc/gcc-4.8.5/include/c++/4.8.5/backward/auto_ptr.h:87) [-Wdeprecated-declarations]
   vector< auto_ptr<int> > a_v;  //USAGE ERROR
           ^
>./test1
is_copy_constructible:
auto_ptr: false
unique_ptr: false
shared_ptr: true
i_v=1
i_v2=1
u_v=2
s_v=3
s_v2=3
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.