ฉันรับรู้ถึง 5 หมวดหมู่ทั่วไปที่คอมไพล์คอมไพเลอร์ C ++ 03 อีกครั้งเนื่องจาก C ++ 11 สามารถทำให้ประสิทธิภาพเพิ่มขึ้นอย่างไม่ จำกัด ซึ่งไม่เกี่ยวข้องกับคุณภาพของการใช้งานจริง นี่คือความหมายของการย้าย
std::vector
กำหนดใหม่
struct bar{
std::vector<int> data;
};
std::vector<bar> foo(1);
foo.back().data.push_back(3);
foo.reserve(10); // two allocations and a delete occur in C++03
เวลาทุกfoo
's บัฟเฟอร์จะจัดสรรใน C ++ 03 มันคัดลอกทุกในvector
bar
ใน C ++ 11 แทนที่จะเป็นการย้ายbar::data
s ซึ่งโดยพื้นฐานแล้วจะว่าง
ในกรณีนี้นี้ต้องอาศัยการเพิ่มประสิทธิภาพภายในภาชนะstd
vector
ในทุกกรณีด้านล่างการใช้std
คอนเทนเนอร์เป็นเพราะมันเป็นวัตถุ C ++ ที่มีmove
ความหมายที่มีประสิทธิภาพใน C ++ 11 "อัตโนมัติ" เมื่อคุณอัพเกรดคอมไพเลอร์ของคุณ วัตถุที่ไม่ได้บล็อกมันที่มีstd
คอนเทนเนอร์ยังสืบทอดตัวmove
สร้างการปรับปรุงอัตโนมัติ
ความล้มเหลวของ NRVO
เมื่อ NRVO (การเพิ่มประสิทธิภาพค่าที่ส่งคืนที่ระบุชื่อ) ล้มเหลวใน C ++ 03 จะกลับไปคัดลอกบน C ++ 11 จะกลับไปที่การย้าย ความล้มเหลวของ NRVO นั้นง่าย:
std::vector<int> foo(int count){
std::vector<int> v; // oops
if (count<=0) return std::vector<int>();
v.reserve(count);
for(int i=0;i<count;++i)
v.push_back(i);
return v;
}
หรือแม้กระทั่ง:
std::vector<int> foo(bool which) {
std::vector<int> a, b;
// do work, filling a and b, using the other for calculations
if (which)
return a;
else
return b;
}
เรามีสามค่า - ค่าส่งคืนและสองค่าที่แตกต่างกันภายในฟังก์ชั่น Elision อนุญาตให้ค่าในฟังก์ชั่น 'รวม' กับค่าส่งคืน แต่ไม่ได้อยู่ด้วยกัน ทั้งสองไม่สามารถผสานกับค่าส่งคืนโดยไม่รวมเข้าด้วยกัน
ปัญหาพื้นฐานคือ NRision elision มีความเปราะบางและรหัสที่มีการเปลี่ยนแปลงที่ไม่ได้อยู่ใกล้return
ไซต์สามารถทำให้ประสิทธิภาพลดลงอย่างมากที่จุดนั้นโดยไม่มีการวินิจฉัยออกมา ในกรณีที่ความล้มเหลวของ NRVO ส่วนใหญ่ C ++ 11 จบลงด้วย a move
ในขณะที่ C ++ 03 จบลงด้วยการคัดลอก
ส่งคืนอาร์กิวเมนต์ของฟังก์ชัน
Elision เป็นไปไม่ได้ที่นี่:
std::set<int> func(std::set<int> in){
return in;
}
ใน C ++ 11 มีราคาถูก: ใน C ++ 03 ไม่มีวิธีหลีกเลี่ยงการคัดลอก ไม่สามารถลบอาร์กิวเมนต์ของฟังก์ชันด้วยค่าส่งคืนได้เนื่องจากอายุการใช้งานและตำแหน่งของพารามิเตอร์และค่าส่งคืนถูกจัดการโดยรหัสการโทร
อย่างไรก็ตาม C ++ 11 สามารถย้ายจากที่หนึ่งไปอีกที่หนึ่ง (ในตัวอย่างของเล่นที่น้อยกว่าอาจมีบางสิ่งที่ทำให้set
)
push_back
หรือ insert
ในที่สุดการตัดลงในคอนเทนเนอร์จะไม่เกิดขึ้น: แต่ C ++ 11 โอเวอร์โหลด rvalue ย้ายตัวดำเนินการแทรกซึ่งบันทึกสำเนา
struct whatever {
std::string data;
int count;
whatever( std::string d, int c ):data(d), count(c) {}
};
std::vector<whatever> v;
v.push_back( whatever("some long string goes here", 3) );
ใน C ++ 03 ชั่วคราวถูกสร้างขึ้นแล้วมันจะคัดลอกลงในเวกเตอร์whatever
มีการจัดสรรบัฟเฟอร์v
2 ตัวstd::string
โดยแต่ละชุดมีข้อมูลเหมือนกันและอีกหนึ่งตัวจะถูกทิ้ง
ใน C ++ 11 whatever
จะมีการสร้างชั่วคราว whatever&&
push_back
เกินแล้วmove
s v
ที่ชั่วคราวลงในเวกเตอร์ std::string
มีการจัดสรรบัฟเฟอร์หนึ่งรายการและย้ายไปยังเวกเตอร์ ว่างเปล่าstd::string
ถูกทิ้ง
การมอบหมาย
ถูกขโมยจากคำตอบของ @ Jarod42 ด้านล่าง
Elision ไม่สามารถเกิดขึ้นได้กับการมอบหมาย แต่ย้ายจากสามารถ
std::set<int> some_function();
std::set<int> some_value;
// code
some_value = some_function();
ที่นี่some_function
ส่งกลับผู้สมัครที่จะหลบหนี แต่เนื่องจากมันไม่ได้ใช้เพื่อสร้างวัตถุโดยตรงจึงไม่สามารถถูกตัดออกได้ ใน C ++ 03 some_value
ผลดังกล่าวข้างต้นในเนื้อหาของความเป็นอยู่ชั่วคราวคัดลอกลง ใน C ++ 11 จะถูกย้ายเข้าsome_value
ซึ่งโดยทั่วไปจะว่าง
เพื่อให้ได้เอฟเฟกต์แบบเต็มรูปแบบข้างต้นคุณต้องมีคอมไพเลอร์ที่สังเคราะห์ตัวสร้างการย้ายและการมอบหมายสำหรับคุณ
MSVC 2013 ใช้ตัวสร้างย้ายในstd
คอนเทนเนอร์ แต่ไม่สังเคราะห์ตัวสร้างย้ายในประเภทของคุณ
ดังนั้นประเภทที่มีstd::vector
s และที่คล้ายกันจะไม่ได้รับการปรับปรุงใน MSVC2013 แต่จะเริ่มได้ใน MSVC2015
เสียงดังกราวและ gcc มีความยาวตั้งแต่นำไปใช้กับตัวสร้างการเคลื่อนย้ายโดยนัย อินเทล 2013 คอมไพเลอร์จะให้การสนับสนุนการสร้างโดยนัยของการก่อสร้างย้ายถ้าคุณผ่าน-Qoption,cpp,--gen_move_operations
(พวกเขาไม่ได้ทำมันโดยเริ่มต้นในความพยายามที่จะข้ามเข้ากันได้กับ MSVC2013 เป็นพิเศษ)