2016-07-06 13 views
7

Tôi có một lớp không thể kiểm tra. Sao chép này sẽ là vấn đề. Tôi muốn đảm bảo rằng nó sẽ không được bao giờ sao chép, vì vậy tôi làm bản sao của nó constructor deleted:Làm thế nào để thực thi sao chép elision, tại sao nó sẽ không làm việc với các nhà xây dựng bản sao đã xóa?

class A { 
    public: 
    A(); 
    A(const A&) = delete; 
}; 

A fun() { 
    return A(); 
}; 

int main() { 
    A a = fun(); 
}; 

Thật không may, g ++ sẽ không biên dịch này vào lý do:

t.cc: In function ‘A fun()’: 
t.cc:8:12: error: use of deleted function ‘A::A(const A&)’ 
    return A(); 
      ^
t.cc:4:5: note: declared here 
    A(const A&) = delete; 
    ^
t.cc: In function ‘int main()’: 
t.cc:12:13: error: use of deleted function ‘A::A(const A&)’ 
    A a = fun(); 
      ^
t.cc:4:5: note: declared here 
    A(const A&) = delete; 
    ^

Nhưng đây là một tình huống rất rõ ràng khi sử dụng sao chép bản sao, do đó, các nhà xây dựng sao chép không nên được gọi. Tại sao nó như vậy?

+1

Đợi đến khi C++ 17, có thể nó sẽ được đảm bảo –

+0

Rất tiếc. Đã chuyển để trả lời. –

+1

Jesper không lặp lại câu trả lời của bạn, bạn không đề cập đến những thay đổi sắp tới cho đến khi nhận xét của chúng tôi –

Trả lời

9

Cho đến khi C++ 17 sao chép elision là một tối ưu hóa trình biên dịch là không cần thiết để làm, vì vậy các lớp phải được sao chép vì trình biên dịch có thể muốn sao chép (ngay cả khi nó thực sự không). Trong C + + 17 sao chép elision sẽ được đảm bảo trong nhiều trường hợp và sau đó các lớp học sẽ không cần bản sao ctors.

Xem thêm:

http://en.cppreference.com/w/cpp/language/copy_elision

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0135r0.html

https://herbsutter.com/2016/06/30/trip-report-summer-iso-c-standards-meeting-oulu/ (bit về "sao chép sự bỏ bớt được đảm bảo")

Bạn có lẽ có thể sử dụng các thủ thuật cũ của tuyên bố các nhà xây dựng bản sao trong lớp học của bạn nhưng không thực sự thực hiện nó? Điều đó sẽ làm hài lòng trình biên dịch miễn là nó không thực sự gọi ctor sao chép. Tôi đã không kiểm tra điều đó, nhưng tôi tin rằng nó sẽ làm việc cho trường hợp của bạn cho đến khi C + + 17 đến.

8

Bạn không thể buộc bắt chước bản sao (chưa) (xem các câu trả lời khác).

Tuy nhiên, bạn có thể cung cấp hàm khởi động mặc định cho lớp của mình, điều này sẽ di chuyển (và do đó, không sao chép) giá trị trả về nếu không thể thực hiện RVO/NRVO. Để làm điều này bạn nên thêm = default cho nhà xây dựng di chuyển của bạn:

class A { 
    public: 
    A() = default; 
    A(const A&) = delete; 
    A(A&&) = default; 
    A& operator=(A&&) = default; 
}; 

Example

+0

Tôi không thể hiểu được, đặc biệt là không có lời giải thích. – peterh

+1

@peterh Có lẽ vì nó không trả lời câu hỏi bạn đã hỏi. – juanchopanza

+0

Ok, nhưng tại sao các nhà thầu di chuyển là cần thiết? Cấu trúc duy nhất cần được gọi trong ví dụ này, là hàm tạo rỗng. Không di chuyển thực sự xảy ra. – peterh

7

giá trị Return tối ưu hóa (RVO và NRVO) không có nghĩa là yêu cầu rằng các loại tham gia bằng cách copyable hoặc di chuyển được giảm. Yêu cầu này được áp dụng, cho dù bạn có được RVO hay không.

Lý do có nhiều khả năng nhất là quá trình này không được thực thi. Đó là một tối ưu hóa rằng có thể diễn ra và sẽ không có ý nghĩa đối với mã để biên dịch hay không dựa trên việc tối ưu hóa đó có được áp dụng trong một triển khai cụ thể hay không.

Trong C++ 17, RVO sẽ được thực thi trong một số trường hợp và yêu cầu về khả năng sao chép và di chuyển sẽ bị xóa.

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