Trong bài nói chuyện GoingNative 2013 của mình, Scott Meyers đã chỉ ra rằng std::move
không đảm bảo rằng mã được tạo sẽ thực sự thực hiện di chuyển.Buộc lỗi thời gian biên dịch nếu std :: di chuyển sẽ dẫn đến bản sao không mong muốn?
Ví dụ:
void foo(std::string x, const std::string y) {
std::string x2 = std::move(x); // OK, will be moved
std::string y2 = std::move(y); // compiles, but will be copied
}
Ở đây, các nhà xây dựng di chuyển không thể áp dụng nhưng vì độ phân giải quá tải, các nhà xây dựng bản sao bình thường sẽ được sử dụng để thay thế. Tùy chọn dự phòng này có thể rất quan trọng đối với khả năng tương thích ngược với mã C++ 98, nhưng trong ví dụ trên, rất có thể đó không phải là ý tưởng của lập trình viên.
Có cách nào để thực thi rằng một hàm tạo di chuyển sẽ được gọi?
Ví dụ: giả sử bạn muốn di chuyển một ma trận lớn. Nếu ứng dụng của bạn thực sự phụ thuộc vào Ma trận để được di chuyển, nó sẽ là tuyệt vời để ngay lập tức nhận được một lỗi biên dịch nếu một động thái là không thể. (Nếu không, vấn đề về hiệu suất có thể trượt dễ dàng thông qua các bài kiểm tra đơn vị và bạn sẽ chỉ tìm ra sau khi một số hồ sơ.)
Cho phép gọi di chuyển được đảm bảo này strict_move
. Tôi muốn có thể viết mã như sau:
void bar(Matrix x, const Matrix y) {
Matrix x2 = strict_move(x); // OK
Matrix y2 = strict_move(y); // compile error
}
Có thể không?
Edit:
Cảm ơn câu trả lời tuyệt vời! Có một số yêu cầu hợp pháp để làm rõ câu hỏi của tôi:
- Nếu
strict_move
không thành công nếu đầu vào là const? - Nếu
strict_move
không thành công nếu kết quả sẽ không dẫn đến hoạt động di chuyển thực tế (mặc dù bản sao có thể nhanh như di chuyển, ví dụ:const complex<double>
)? - Cả hai?
Ý tưởng ban đầu của tôi rất mơ hồ: Tôi coi các ví dụ của Scott Meyers khá đáng báo động, vì vậy tôi tự hỏi liệu có thể có trình biên dịch ngăn các bản sao không mong muốn đó không.
Scott Meyers được đề cập trong bài nói chuyện của mình rằng một cảnh báo trình biên dịch chung không phải là một tùy chọn vì nó sẽ dẫn đến một số lượng lớn một sai tích cực. Thay vào đó, tôi muốn giao tiếp với trình biên dịch giống như "Tôi chắc chắn 100% rằng điều này phải luôn dẫn đến hoạt động di chuyển và bản sao quá đắt đối với loại cụ thể này".
Vì vậy, tôi đã tự ý nói rằng strict_move
sẽ không thành công trong cả hai trường hợp. Trong khi đó tôi không chắc điều gì sẽ là tốt nhất. Một khía cạnh khác mà tôi không xem xét là noexcept
.
Từ phía tôi, ngữ nghĩa chính xác của strict_move
đang mở. Tất cả mọi thứ giúp ngăn ngừa một số sai lầm ngu ngốc tại thời gian biên dịch mà không có những hạn chế nghiêm trọng là tốt.
Tạo phiên bản 'di chuyển' của riêng bạn để kiểm tra kiểu trả về? –
Đợi đã, bạn có muốn kiểm tra xem đầu vào không phải là const hay bạn muốn kiểm tra xem di chuyển thực sự có xảy ra hay không. Bởi vì thứ hai là một ý tưởng tồi, và các câu trả lời dưới đây bỏ qua sự giải thích đó. –
@MooingDuck Thú vị, tôi đã không nghĩ về sự khác biệt đó một cách chi tiết, tôi chỉ muốn có một mạng lưới an toàn chống lại hành vi không chủ ý. Tôi đồng ý rằng việc ngăn chặn việc di chuyển đối tượng 'const' là an toàn hơn, nhưng các đối số chống lại việc kiểm tra bổ sung thêm rằng một hàm tạo di chuyển là có sẵn và sẽ được gọi là gì? Tôi có thể hiểu rằng việc sử dụng cấu trúc như vậy trong mã thư viện có thể làm cho mã không linh hoạt vì nó loại trừ tất cả các lớp mà không cần chuyển các hàm tạo và có thể gây ra các vấn đề với các chuyển đổi. Nhưng nhược điểm của việc sử dụng nó chỉ trong phần hiệu năng quan trọng của cơ sở mã của riêng bạn là gì? –