2015-11-02 14 views
5

Giả sử tôi có:Sự khác nhau giữa auto a = A (3) và A a (3) là gì?

struct A 
{ 
    A(int x) : m_x(x) { } 
    A(A&&) = delete; 
    int m_x; 
} 

và:

A a(3); // Ok 
auto a = A(3); // Error: function A(int&&) cannot be referenced - it's a deleted function 

Tại sao cuộc gọi thứ hai để các nhà xây dựng di chuyển? Tại sao hai câu lệnh này khác nhau về mã được tạo?

Trả lời

4

Tại sao bạn mong đợi cả hai đường dẫn mã sẽ giống nhau?

Rõ ràng là bạn đang xây dựng một đối tượng chưa được đặt tên trong ví dụ thứ hai, phân bổ a (auto a) và sau đó sao chép từ tạm thời sang a (đây là di chuyển vì chúng ta đang nói về một đối tượng tạm thời).

+0

Về nhận xét đầu tiên của bạn, ấn tượng của tôi là điều này thường được giới thiệu là "chúng giống nhau, ngoại trừ các kỹ thuật thường không xuất hiện". Nhưng có lẽ tôi đang nói những từ trong miệng OP. – Hurkyl

+1

Bất cứ ai giới thiệu chúng như vậy sẽ bị sa thải vì không đủ năng lực. – Blindy

+0

Tại sao trình biên dịch sẽ tạo ra các mã khác nhau khi mục đích rõ ràng là giống nhau? Có trường hợp lập trình viên muốn hành vi đó không? – Shmoopy

-1

Không quan trọng trình biên dịch sẽ tạo cùng một mã trong cả hai trường hợp, bởi vì tại thời gian biên dịch, các hàm/hàm dựng cần thiết cần được xác định. Hãy suy nghĩ về nó theo cách này - tối ưu hóa sẽ xảy ra sau khi biên dịch/phân tích cú pháp mã, nhưng trong mã kết thúc willbe (nên-be) giống nhau trong trường hợp này.

+0

sẽ được biên dịch sang cùng một mã máy * với các tối ưu hóa trên * – CoffeeandCode

6

auto a = A(3); có nghĩa là giống như A a = A(3); vì loại bên tay phải là A.

Điều này có nghĩa chính xác những gì nó trông giống như: A(3) tạo ra một tạm thời A khởi tạo với 3, và sau đó A a = _____ có nghĩa là: tạo ra một A gọi a với _____ như khởi tạo.

Vì vậy, bạn tạo tạm thời, chuyển cho a làm trình khởi tạo và sau đó tạm thời bị hủy. Loại khởi tạo này (với =) được gọi là sao chép-khởi tạo (mặc dù không nhầm lẫn rằng với "sao chép", nó chỉ là một từ).

Một nhà xây dựng được chọn để xây dựng a chấp nhận A. Đây phải là một bản sao hoặc một hàm khởi tạo. A có một hàm tạo di chuyển và một hàm tạo bản sao. Cái sau được ngầm tạo ra và được định nghĩa là đã bị xóa, bởi vì có một hàm tạo di chuyển do người dùng khai báo.

Được định nghĩa là đã xóa không ảnh hưởng đến độ phân giải quá tải; và hàm khởi tạo (move-constructor) được ưu tiên cho hàm tạo bản sao trong trường hợp này.

Vì vậy, mã của bạn cố gắng gọi hàm delete d, không đúng định dạng, do đó lỗi.

Lưu ý rằng nếu di chuyển-constructor không bị xóa, sau đó sao chép elision sẽ được áp dụng. Nó khởi động trong một số trường hợp mà một biến được khởi tạo từ một biến tạm thời hoặc một biến cục bộ được trả về bởi giá trị. Quy tắc là trình biên dịch có thể sử dụng cùng một bộ nhớ cho cả a và đối tượng tạm thời và bỏ qua cuộc gọi đến trình tạo bản sao/di chuyển.

Hầu hết/tất cả trình biên dịch thực sự sẽ thực hiện việc này trong hoàn cảnh. Vì vậy, bạn thực sự có thể viết auto a = A(3); và trong thực tế không nhận được bất kỳ động thái không cần thiết nào. Nếu bạn viết một số mã cho hàm khởi tạo của bạn để xuất ra một cái gì đó, bạn hy vọng sẽ thấy rằng không có gì là đầu ra.

Nếu bạn muốn hoàn toàn chắc chắn không có bản sao không cần thiết, hoặc xây dựng một đối tượng không có bản sao có thể sử dụng hoặc chuyển nhà xây dựng - hãy dừng viết mã chỉ định các bản sao không cần thiết! A a(3); là đủ.

+0

Tôi tự hỏi, liệu trình biên dịch có được phép di chuyển trong trường hợp này, nơi mà hàm khởi động di chuyển bị xóa không? – Mikhail

+0

@Mikhail xin lỗi, đã đọc sai câu hỏi. sẽ cập nhật câu trả lời của tôi –

Các vấn đề liên quan