2012-10-29 27 views
16

Tôi đang bối rối khi một nhà xây dựng di chuyển được gọi là một hàm tạo bản sao. Tôi đã đọc các nguồn sau:Khi nào Move Constructor được gọi?

Move constructor is not getting called in C++0x

Move semantics and rvalue references in C++11

msdn

Tất cả những nguồn được một trong hai overcomplicated (Tôi chỉ muốn có một ví dụ đơn giản) hoặc chỉ hiển thị như thế nào để viết một di chuyển constructor, nhưng không phải làm thế nào để gọi nó. Ive đã viết một vấn đề đơn giản để cụ thể hơn:

const class noConstruct{}NoConstruct; 
class a 
{ 
private: 
    int *Array; 
public: 
    a(); 
    a(noConstruct); 
    a(const a&); 
    a& operator=(const a&); 
    a(a&&); 
    a& operator=(a&&); 
    ~a(); 
}; 

a::a() 
{ 
    Array=new int[5]{1,2,3,4,5}; 
} 
a::a(noConstruct Parameter) 
{ 
    Array=nullptr; 
} 
a::a(const a& Old): Array(Old.Array) 
{ 

} 
a& a::operator=(const a&Old) 
{ 
    delete[] Array; 
    Array=new int[5]; 
    for (int i=0;i!=5;i++) 
    { 
     Array[i]=Old.Array[i]; 
    } 
    return *this; 
} 
a::a(a&&Old) 
{ 
    Array=Old.Array; 
    Old.Array=nullptr; 
} 
a& a::operator=(a&&Old) 
{ 
    Array=Old.Array; 
    Old.Array=nullptr; 
    return *this; 
} 
a::~a() 
{ 
    delete[] Array; 
} 

int main() 
{ 
    a A(NoConstruct),B(NoConstruct),C; 
    A=C; 
    B=C; 
} 

hiện tại A, B và C đều có giá trị con trỏ khác nhau. Tôi muốn A có một con trỏ mới, B để có con trỏ cũ của C, và C để có một con trỏ null.

phần nào tắt chủ đề, nhưng nếu có thể đề xuất tài liệu mà tôi có thể tìm hiểu về các tính năng mới này, tôi sẽ biết ơn và có thể không cần hỏi thêm nhiều câu hỏi nữa.

+0

Trên một vấn đề liên quan đến một phần, bạn có thể muốn kiểm tra bản sao và hoán đổi thành ngữ http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom cho bài tập của bạn nhà điều hành. – undu

+0

[Câu hỏi thường gặp liên quan] (http: // stackoverflow.com/questions/3106110 /) – fredoverflow

Trả lời

22

Một constructor di chuyển được gọi là:

  • khi một đối tượng khởi tạo là std::move(something)
  • khi một đối tượng khởi tạo là std::forward<T>(something)T không phải là một loại tài liệu tham khảo giá trị trái (hữu dụng trong mẫu lập trình cho "hoàn hảo chuyển tiếp ")
  • khi bộ khởi tạo đối tượng tạm thời và trình biên dịch không loại bỏ bản sao/di chuyển hoàn toàn
  • khi trả về đối tượng lớp cục bộ theo giá trị và trình biên dịch không loại bỏ bản sao/di chuyển hoàn toàn
  • khi ném đối tượng lớp địa phương hàm và trình biên dịch không loại bỏ bản sao/di chuyển hoàn toàn

Đây không phải là danh sách đầy đủ. Lưu ý rằng một "bộ khởi tạo đối tượng" có thể là đối số hàm, nếu tham số có loại lớp (không phải tham chiếu).

a RetByValue() { 
    a obj; 
    return obj; // Might call move ctor, or no ctor. 
} 

void TakeByValue(a); 

int main() { 
    a a1; 
    a a2 = a1; // copy ctor 
    a a3 = std::move(a1); // move ctor 

    TakeByValue(std::move(a2)); // Might call move ctor, or no ctor. 

    a a4 = RetByValue(); // Might call move ctor, or no ctor. 

    a1 = RetByValue(); // Calls move assignment, a::operator=(a&&) 
} 
4

Trước hết, hàm tạo bản sao của bạn bị hỏng. Cả hai sao chép từ và sao chép vào các đối tượng sẽ trỏ đến cùng một Array và cả hai sẽ cố gắng để delete[] nó khi họ đi ra khỏi phạm vi, dẫn đến hành vi không xác định. Để khắc phục, hãy sao chép mảng.

a::a(const a& Old): Array(new int[5]) 
{ 
    for(size_t i = 0; i < 5; ++i) { 
    Array[i] = Old.Array[i]; 
    } 
} 

Bây giờ, việc chuyển nhượng sẽ không được thực hiện như bạn muốn, bởi vì cả hai câu lệnh gán đều được gán từ giá trị thay vì sử dụng giá trị. Để di chuyển được thực hiện, bạn phải di chuyển từ một rvalue, hoặc nó phải là một bối cảnh mà một lvalue có thể được coi là một rvalue (chẳng hạn như câu lệnh return của một hàm).

Để sử dụng hiệu quả mong muốn std::move để tạo tham chiếu rvalue.

A=C;    // A will now contain a copy of C 
B=std::move(C); // Calls the move assignment operator 
+0

'B = std :: move (C); // Gọi toán tử gán bản sao' Không phải nó là toán tử gán di chuyển? Sau đó, C có thể không còn là những gì nó được sử dụng để. – RainingChain

+0

@RainingChain Vâng, đó là lỗi đánh máy, cảm ơn! – Praetorian

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