2015-04-30 19 views
6

Trong một thời gian, điều này làm tôi bối rối. Và tôi đã không thể tìm thấy một câu trả lời thỏa đáng cho đến nay. Câu hỏi rất đơn giản. Khi nào thì move assignment operator được gọi và khi nào thì gọi số move constructor operator?Sự khác biệt giữa toán tử gán chuyển và di chuyển hàm tạo?

Các ví dụ mã trên cppreference.com mang lại kết quả thú vị sau:

The move assignment operator:

a2 = std::move(a1); // move-assignment from xvalue 

The move constructor:

A a2 = std::move(a1); // move-construct from xvalue 

Vì vậy, đã nó làm gì để có được thực hiện? Và nếu như vậy được thực hiện nếu cả hai được thực hiện? Và tại sao có khả năng tạo ra một toán tử chuyển nhượng quá tải ở tất cả, nếu nó giống hệt nhau.

Trả lời

11

Một hàm tạo di chuyển chỉ được thực thi khi bạn xây dựng một đối tượng. Một toán tử gán di chuyển được thực thi trên một đối tượng đã được tạo trước đó. Đó là chính xác cùng một kịch bản như trong trường hợp sao chép.

Foo foo = std::move(bar); // construction, invokes move constructor 
foo = std::move(other); // assignment, invokes move assignment operator 

Nếu bạn không khai báo rõ ràng, trình biên dịch sẽ tạo chúng cho bạn (với một số ngoại lệ, danh sách quá dài sẽ được đăng ở đây).

Xem this để biết câu trả lời đầy đủ cho thời điểm các hàm thành viên di chuyển được tạo ra ngầm.

2

Điều này tương tự như gán bản sao bình thường và xây dựng bản sao.

A a2 = std::move(a1); 
A a2 = a1; 

Những người gọi là nhà xây dựng di chuyển/sao chép, vì a2 chưa tồn tại và cần được xây dựng. Chỉ định không có ý nghĩa. Biểu mẫu này được gọi là khởi tạo sao chép.

a2 = std::move(a1); 
a2 = a1; 

Gọi là nhà điều hành chuyển nhượng/sao chép vì a2 đã tồn tại nên không có ý nghĩa khi xây dựng nó.

4

Khi nào thì một toán tử gán di chuyển được gọi

Khi bạn gán một rvalue đến một đối tượng, như bạn làm trong ví dụ đầu tiên của bạn.

và khi nào một nhà điều hành nhà xây dựng di chuyển được gọi?

Khi bạn khởi tạo đối tượng bằng cách sử dụng rvalue, như bạn làm trong ví dụ thứ hai của mình. Mặc dù nó không phải là một nhà điều hành.

Vì vậy, nó đã làm gì để được triển khai?

Không, điều đó xác định xem nó có thể được sử dụng, không khi nào nó có thể được sử dụng.Ví dụ, nếu không có hàm khởi tạo, thì việc xây dựng sẽ sử dụng hàm tạo bản sao nếu nó tồn tại và không thành công (có lỗi).

Và nếu điều đó được thực hiện nếu cả hai được triển khai?

Nhà điều hành chuyển nhượng cho nhiệm vụ, người xây dựng để khởi tạo.

Và tại sao có khả năng tạo một toán tử gán nhiệm vụ di chuyển quá tải, nếu nó giống hệt nhau.

Nó không giống nhau. Nó được gọi trên một đối tượng đã tồn tại; constructor được gọi để khởi tạo một đối tượng mà trước đó không tồn tại. Họ thường phải làm những việc khác nhau. Ví dụ, nhiệm vụ có thể phải xóa một cái gì đó, mà sẽ không tồn tại trong quá trình khởi tạo.

0

Move constructor được gọi là trong suốt:

  • khởi: T a = std :: di chuyển (b); hoặc T a (std :: move (b)) ;, trong đó b là loại T;
  • chuyển đối số hàm: f (std :: move (a)) ;, trong đó một loại T và f là void f (T t);

Move hoạt động chuyển nhượng được gọi là trong suốt:

  • hàm trả về: return a; bên trong một hàm như T f(), trong đó một là kiểu T có một hàm tạo di chuyển.
  • phân

Đoạn mã ví dụ sau đây minh họa điều này:

#include <iostream> 
#include <utility> 
#include <vector> 
#include <string> 
using namespace std; 
class A { 
    public : 
    A() { cout << "constructor called" << endl;} 
    ~A() { cout << "destructor called" << endl;} 
    A(A&&) {cout << "move constructor called"<< endl; return;} 
    A& operator=(A&&) {cout << "move assignment operator called"<< endl; return *this;} 

}; 
A fun() { 
    A a; // 5. constructor called 
    return a; // 6. move assignment operator called 
    // 7. destructor called on this local a 
} 
void foo(A){ 
    return; 
} 
int main() 
{ 
    A a; // 1. constructor called 
    A b; // 2. constructor called 
    A c{std::move(b)}; // 3. move constructor called 
    c = std::move(a); // 4. move assignment operator called 
    a = fun(); 
    foo(std::move(c)); // 8. move constructor called 

} 

Output:

constructor called 
constructor called 
move constructor called 
move assignment operator called 
constructor called 
move assignment operator called 
destructor called 
move constructor called 
destructor called 
destructor called 
destructor called 
destructor called 
+0

"lập luận chức năng đi qua" là một trường hợp đặc biệt của "khởi tạo" và tôi không chắc chắn ý của bạn là "trả về hàm". –

+0

'return a;' không phải là mote-assignment –

+0

@ M.M: hãy giúp tôi hiểu điều này khi in ra 6 (từ bên trong fun() khai báo) là toán tử gán di chuyển được gọi. – novieq

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