2012-06-18 27 views
7

Tôi biết rằng khi truyền một đối tượng theo giá trị cho hàm, hàm tạo di chuyển luôn được gọi nếu có, giả sử không có phép sao chép bản sao. Điều gì về việc trả về một đối tượng theo giá trị?Đối tượng có được bảo đảm di chuyển khi nó được trả về không?

Ví dụ: giả sử chúng tôi có một lớp Foo trong đó có hàm tạo di chuyển và chúng tôi có hàm trả về đối tượng Foo.

Foo g() { 
    Foo f; 

    // do something with f 

    return f; 
} 

Nếu chúng tôi giả định không có RVO, thì hàm tạo di chuyển có được bảo đảm không?

Cập nhật: Tôi đoán tôi không thể hiện rõ ý định của mình. Tôi chỉ muốn biết tôi có thể trong trường hợp xấu nhất có đối tượng di chuyển không sao chép. Hoặc RVO hoặc NRVO xảy ra, tôi hạnh phúc. Và tôi cũng nên nói rằng nhà xây dựng di chuyển và chuyển nhượng sẽ không bị xóa và được triển khai đúng cách.

+0

Có, đối tượng địa phương trong lưu trữ tự động được xử lý ngầm như xvalues ​​trong câu lệnh trả về. – ildjarn

+0

@ildjarn: Tôi nghĩ rằng chỉ khi bạn trả lại trực tiếp. Một nơi nào đó trên SO tôi đã được sửa chữa từ nói rằng điều này di chuyển 'f' vào hàm:' return do_something (f); '. – GManNickG

+0

@GManNickG: Tôi không có thời gian cho các tiêu chuẩn hoặc hãy cẩn thận, do đó một bình luận chứ không phải là một câu trả lời. Tôi nghĩ bạn đã đúng. : -] – ildjarn

Trả lời

4

Có. Xem [lớp học.bản sao] p32

Khi tiêu chí cho phép cắt bỏ hoạt động sao chép được đáp ứng hoặc sẽ được lưu để thực tế đối tượng nguồn là thông số chức năng và đối tượng được sao chép được chỉ định bởi giá trị quá tải độ phân giải để chọn hàm tạo cho bản sao được thực hiện đầu tiên như thể đối tượng được chỉ định bởi một giá trị. Nếu độ phân giải quá tải không thành công, hoặc nếu kiểu tham số đầu tiên của hàm tạo đã chọn không phải là tham chiếu rvalue đến loại đối tượng (có thể là đủ điều kiện cv), thì độ phân giải quá tải sẽ được thực hiện lại, xem xét đối tượng dưới dạng giá trị. [Lưu ý: Độ phân giải quá tải hai giai đoạn này phải được thực hiện bất kể việc quét bản sao có xảy ra hay không. Nó xác định constructor được gọi nếu không thực hiện elision, và constructor đã chọn phải được truy cập ngay cả khi cuộc gọi được elided. - lưu ý cuối]

+0

+1 cho trích dẫn tiêu chuẩn cần thiết. – ildjarn

2

Trong trường hợp này, vì giá trị trả về có tên (f), nó sẽ là NRVO (được đặt tên là tối ưu hóa trả về) sẽ áp dụng.

Vì vậy, câu trả lời kỹ thuật chỉ dựa trên từ ngữ, là sự vắng mặt của RVO sẽ không ngăn chặn sao chép elision, vì NRVO vẫn có thể cho phép nó.

Qua đó, tôi tin rằng lựa chọn giữa di chuyển/bản sao của giá trị trả lại có thể/sẽ tùy thuộc vào định nghĩa của Foo - chắc chắn là nó sẽ được sao chép thay vì di chuyển, chẳng hạn như nếu bạn đã rõ ràng đã xóa hàm khởi tạo di chuyển và di chuyển các toán tử gán, hoặc bạn chưa định nghĩa di chuyển/chuyển nhượng và nó không đủ điều kiện để chúng được tổng hợp hoàn toàn.

Chỉnh sửa: [trả lời câu hỏi đã chỉnh sửa]: Việc tạo hàm tạo di chuyển vẫn không đảm bảo rằng kết quả sẽ được di chuyển. Một ví dụ rõ ràng là nếu bạn đã xóa toán tử gán di chuyển và đã gán kết quả (thay vì sử dụng nó để khởi tạo). Trong trường hợp này, toán tử gán di chuyển đã xóa sẽ ngăn di chuyển giá trị trả về.

Để trả lời những gì bạn có thể nhận được, tuy nhiên, quy tắc chung là di chuyển sẽ được thực hiện nếu có thể và sẽ quay trở lại để sao chép nếu và chỉ khi điều gì đó ngăn không cho kết quả bị di chuyển.

+0

Tôi đoán tôi không thể hiện rõ ý định của mình trong câu hỏi. Tôi chỉ muốn biết tôi có thể trong trường hợp xấu nhất có đối tượng di chuyển không sao chép. Hoặc RVO hoặc NRVO xảy ra, tôi hạnh phúc. Và tôi cũng nên nói rằng di chuyển constructor và chuyển nhượng di chuyển không bị xóa. Cảm ơn. – haotang

+3

@Jerry: Có hai bản sao tiềm năng trong mã đó. Đầu tiên là từ biến cục bộ đến câu lệnh trả về, thường được gọi là (N) RVO. Đó là đảm bảo không sao chép nếu có một nhà xây dựng di chuyển, trình biên dịch có thể áp dụng (N) RVO hay không, nhưng nếu nó không * phải * di chuyển xây dựng. Bản sao tiềm năng thứ hai nằm ở phía người gọi, từ đối tượng được trả về và nằm ngoài phạm vi của câu hỏi, vì nó phụ thuộc vào mã người gọi, không phụ thuộc vào hàm. –

1

Quy tắc là bất cứ khi nào sao chép phép cắt bỏ nhưng không xảy ra, thì hàm tạo di chuyển sẽ được sử dụng nếu nó có sẵn và nếu không thì hàm tạo bản sao sẽ được sử dụng.

Các hành vi chính xác được xác định bởi [class.copy]/32:

Khi các tiêu chuẩn cho sự bỏ bớt một hoạt động sao chép được đáp ứng hoặc sẽ được đáp ứng tiết kiệm cho một thực tế rằng các đối tượng nguồn là một tham số chức năng, và các đối tượng được sao chép được chỉ định bởi một lvalue, độ phân giải quá tải để chọn constructor cho bản sao được thực hiện đầu tiên như thể đối tượng được chỉ định bởi một rvalue. Nếu độ phân giải quá tải không thành công, hoặc nếu kiểu tham số đầu tiên của hàm tạo đã chọn không phải là tham chiếu rvalue đối với loại đối tượng (có thể cv đủ điều kiện), thì độ phân giải quá tải sẽ được thực hiện lại, xem xét đối tượng dưới dạng giá trị.

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