Nếu bạn không bao giờ tham khảo biến đó nữa, trình biên dịch có được phép di chuyển nó vào đối tượng hàm kết quả không?
No. Tình huống duy nhất mà trình biên dịch được phép thay thế bản sao bằng cử động là các tình huống tương tự chính xác khi được phép thực hiện một bản sao chép. Những tình huống này bao gồm trả về một đối tượng cục bộ theo giá trị hoặc khởi tạo một đối tượng với một tạm thời. Trong những trường hợp này, trình biên dịch được phép bỏ qua bản sao bằng cách tạo nguồn và nhắm mục tiêu cùng một đối tượng. Nếu trình biên dịch không thể thực hiện điều đó vì bất kỳ lý do nào, nó phải xem xét đối tượng nguồn như là một rvalue đối với độ phân giải quá tải để chọn hàm tạo thích hợp cho đối tượng đích. Trong trường hợp của bạn, tuy nhiên, tập tin là một Lvalue và không ai trong số các trường hợp từ trên áp dụng. Bạn sẽ phải sử dụng một động thái rõ ràng.
Thật không may, C++ 11 không có cú pháp cho "di chuyển chụp". IMHO, thật đáng tiếc. Nhưng std :: bind hỗ trợ điều này. Bạn có thể kết hợp std :: bind với một biểu thức lambda như sau:
void foo(char const* p) {
string s = p;
auto fun = bind([](string const& s){
...
},move(s));
fun();
}
để chuỗi được di chuyển vào đối tượng hàm.
Nếu bạn có ý định gọi chức năng này chỉ một lần và muốn di chuyển chuỗi ra khỏi đối tượng chức năng một lần nữa, bạn có thể sử dụng một tham chiếu không const:
void foo(char const* p) {
string s = p;
auto fun = bind([](string & s) {
some_other_func(move(s));
},move(s));
fun();
}
Lưu ý rằng, nếu bạn không muốn sử dụng ràng buộc ở đây nhưng chúng ta hãy xây dựng các đối tượng lambda tạo một bản sao của s, di chuyển các chuỗi ra khỏi đối tượng chức năng đòi hỏi các từ khóa có thể thay đổi:
void foo(char const* p) {
string s = p;
auto fun = [=]() mutable {
// ^^^^^^^
some_other_func(move(s));
};
fun();
}
bởi vì nếu không điều hành kiểu đóng cửa() chức năng sẽ const- đủ điều kiện mà lần lượt làm cho s
một chuỗi có trình độ const.
Trong C++ 14, điều khoản chụp lambda linh hoạt hơn một chút. Bây giờ chúng ta có thể viết
void foo(char const* p) {
string s = p;
auto fun = [s=move(s)]() mutable { // #1
some_other_func(move(s)); // #2
};
fun();
}
nơi # 1 di chuyển các chuỗi giá trị vào đối tượng lambda và # 2 di chuyển các chuỗi giá trị ra (tùy thuộc vào cách some_other_func
được khai báo chính xác).
Tôi đoán rằng điều này là quá khó để tìm ra nói chung cho trình biên dịch. Bạn có thể cung cấp mã ví dụ không? – fredoverflow
Có quy tắc "như thể" tất nhiên. Nhưng tôi đoán bạn đang nghĩ về một trường hợp mà các ctor sao chép và/hoặc di chuyển ctor có tác dụng phụ, vì vậy bạn có thể nói sự khác biệt. Câu hỏi thú vị. – aschepler
@aschepler: nếu tôi nhớ chính xác, trình biên dịch được phép bỏ qua các tác dụng phụ của các nhà xây dựng sao chép và di chuyển. @ DeadMG: Hình như tôi có thể tối ưu hóa nó đi, bạn đã thử chưa? –