Tôi biết 5 loại chung trong đó biên dịch lại trình biên dịch C ++ 03 vì C ++ 11 có thể gây ra sự gia tăng hiệu suất không giới hạn mà thực tế không liên quan đến chất lượng thực hiện. Đây là tất cả các biến thể của ngữ nghĩa di chuyển.
std::vector
tái phân bổ
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
mỗi khi foo
bộ đệm được phân bổ lại trong C ++ 03, nó được sao chép mọi thứ vector
trong bar
.
Trong C ++ 11, nó thay vào đó di chuyển bar::data
s, về cơ bản là miễn phí.
Trong trường hợp này, điều này phụ thuộc vào tối ưu hóa bên trong std
container vector
. Trong mọi trường hợp dưới đây, việc sử dụng các std
thùng chứa chỉ là vì chúng là các đối tượng C ++ có move
ngữ nghĩa hiệu quả trong C ++ 11 "tự động" khi bạn nâng cấp trình biên dịch. Các đối tượng không chặn nó chứa std
container cũng thừa hưởng các hàm tạo được cải tiến tự động move
.
Thất bại NRVO
Khi NRVO (tối ưu hóa giá trị trả về được đặt tên) không thành công, trong C ++ 03, nó rơi trở lại vào bản sao, trên C ++ 11, nó rơi trở lại khi di chuyển. Thất bại của NRVO rất dễ dàng:
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;
}
hoặc thậm chí:
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;
}
Chúng ta có ba giá trị - giá trị trả về và hai giá trị khác nhau trong hàm. Elision cho phép các giá trị trong hàm được 'hợp nhất' với giá trị trả về, nhưng không cho nhau. Cả hai đều không thể được hợp nhất với giá trị trả về mà không hợp nhất với nhau.
Vấn đề cơ bản là cuộc bầu chọn NRVO rất mong manh và mã với các thay đổi không ở gần return
trang web có thể đột nhiên giảm hiệu suất lớn tại điểm đó mà không có chẩn đoán phát ra. Trong hầu hết các trường hợp thất bại NRVO, C ++ 11 kết thúc bằng a move
, trong khi C ++ 03 kết thúc bằng một bản sao.
Trả về một đối số hàm
Elision cũng là không thể ở đây:
std::set<int> func(std::set<int> in){
return in;
}
trong C ++ 11 này là rẻ: trong C ++ 03 không có cách nào để tránh việc sao chép. Các đối số cho các hàm không thể được tách biệt với giá trị trả về, vì thời gian tồn tại và vị trí của tham số và giá trị trả về được quản lý bởi mã gọi.
Tuy nhiên, C ++ 11 có thể chuyển từ cái này sang cái khác. (Trong một ví dụ đồ chơi ít hơn, một cái gì đó có thể được thực hiện cho set
).
push_back
hoặc là insert
Cuối cùng, việc bỏ trốn vào các thùng chứa không xảy ra: nhưng C ++ 11 quá tải các toán tử chèn di chuyển giá trị, giúp lưu các bản sao.
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) );
trong C ++ 03, tạm thời whatever
được tạo, sau đó nó được sao chép vào vector v
. 2 std::string
bộ đệm được phân bổ, mỗi bộ đệm có dữ liệu giống hệt nhau và một bộ đệm bị loại bỏ.
Trong C ++ 11, tạm thời whatever
được tạo. Quá whatever&&
push_back
tải sau đó move
s mà tạm thời vào vector v
. Một std::string
bộ đệm được phân bổ, và di chuyển vào vector. Một sản phẩm nào std::string
được loại bỏ.
Bài tập
Lấy cắp từ câu trả lời của @ Jarod42 bên dưới.
Elision không thể xảy ra với sự phân công, nhưng di chuyển từ có thể.
std::set<int> some_function();
std::set<int> some_value;
// code
some_value = some_function();
ở đây some_function
trả về một ứng cử viên để tách biệt, nhưng vì nó không được sử dụng để xây dựng một đối tượng trực tiếp, nên nó không thể bị loại bỏ. Trong C ++ 03, các kết quả trên trong nội dung của tạm thời được sao chép vào some_value
. Trong C ++ 11, nó được chuyển vào some_value
, về cơ bản là miễn phí.
Để có hiệu ứng đầy đủ ở trên, bạn cần một trình biên dịch tổng hợp các hàm tạo di chuyển và gán cho bạn.
MSVC 2013 triển khai các hàm tạo di chuyển trong std
các thùng chứa, nhưng không tổng hợp các hàm tạo di chuyển trên các loại của bạn.
Vì vậy, loại có chứa std::vector
s và tương tự không có được những cải tiến như vậy trong MSVC2013, nhưng sẽ bắt đầu nhận được chúng trong MSVC2015.
clang và gcc từ lâu đã thực hiện các hàm tạo di chuyển ngầm. Trình biên dịch 2013 của Intel sẽ hỗ trợ tạo các hàm tạo di chuyển ngầm nếu bạn vượt qua -Qoption,cpp,--gen_move_operations
(mặc định họ không làm điều đó trong nỗ lực tương thích chéo với MSVC2013).