2013-06-06 54 views
14

Tôi hiểu rằng khi chúng tôi xác định hàm tạo bản sao lớp học của lớp là cần thiết như trạng thái Rule of three. Tôi cũng nhận thấy rằng các đối số của các nhà xây dựng bản sao thường là const như các mã sau đây minh họa:Tại sao hàm tạo bản sao C++ phải sử dụng đối tượng const?

class ABC { 
public: 
    int a; 
    int b; 
    ABC(const ABC &other) 
    { 
     a = other.a; 
     b = other.b; 
    } 
} 

Câu hỏi của tôi là những gì sẽ xảy ra nếu đối số của các nhà xây dựng bản sao không phải là const:

class ABC 
{ 
    public: 
    int a; 
    int b; 
    ABC(ABC &other) 
    { 
     a = other.a; 
     b = other.b; 
    } 
} 

Tôi hiểu rằng trong một số trường hợp, nếu đối số của hàm tạo bản sao là const thì việc thực hiện thứ hai sẽ thất bại. Ngoài ra nếu đối số của hàm tạo bản sao là const thì đối tượng được sao chép sẽ không thay đổi nội dung của nó trong suốt quá trình. Tuy nhiên, tôi nhận thấy rằng một số người vẫn sử dụng triển khai thứ hai thay vì thực hiện lần đầu tiên. Có bất kỳ lý do nào mà việc triển khai thứ hai được ưu tiên không?

+4

Tại sao 'A' được sửa đổi trong 'ABC B (A)'? Nó có ý nghĩa rất ít và sẽ là hành vi khá trực quan. – juanchopanza

+8

Có lẽ vì tác giả quên làm cho nó const. –

+0

Nếu chúng ta đi theo tiêu đề của bạn, đây là một bản sao: [Tại sao đối số hàm tạo bản sao const] (http://stackoverflow.com/questions/1602058/why-is-the-copy-constructor-argument-const) (Nếu chúng ta đi đến cuối của văn bản của bạn, nó không phải) – jogojapan

Trả lời

15
  • Một cách logic, nó sẽ làm cho không có ý nghĩa để sửa đổi một đối tượng trong đó bạn chỉ muốn tạo một bản sao, mặc dù đôi khi nó có thể có một số cảm giác, giống như một tình huống mà bạn muốn để lưu trữ các số lượng thời gian đối tượng này đã được sao chép. Nhưng điều này có thể hoạt động với biến thành viên mutable lưu trữ thông tin này và có thể được sửa đổi ngay cả đối với đối tượng const (và điểm thứ hai sẽ biện minh cho phương pháp này)

  • Bạn muốn có thể tạo bản sao của đối tượng const . Nhưng nếu bạn không chuyển đối số của bạn với vòng loại const, thì bạn không thể tạo bản sao của đối tượng const ...

  • Bạn không thể tạo bản sao từ tham chiếu tạm thời, vì đối tượng tạm thời là giá trị và có thể không bị ràng buộc để tham chiếu đến non-const. Đối với một lời giải thích chi tiết hơn, tôi đề nghị Herb Sutter's article on the matter

+3

Có cũng thực tế là phiên bản tham chiếu không phải const sẽ không hoạt động cho thời gian. – juanchopanza

+0

@juanchopanza Bạn nói đúng, tôi đang chỉnh sửa để thêm phần này! – JBL

+0

chỉ là một lưu ý: thậm chí tham chiếu đếm smartpointers không cần mutables. Bộ đếm tham chiếu không nằm trong chính con trỏ thông minh mà thường nằm trong một đối tượng trung gian đặc biệt hoặc bên trong tham chiếu (triển khai xâm nhập). Vì vậy, _smartpointer_ ban đầu vẫn chưa được sửa đổi và có thể được khai báo const. – user396672

1

Sao chép trình xây dựng không được sửa đổi đối tượng mà nó đang sao chép từ đó là lý do tại sao các const được ưu tiên hơn trên thông số other. Cả hai sẽ hoạt động, nhưng const được ưu tiên vì nó nêu rõ rằng đối tượng được truyền vào không nên được sửa đổi bởi hàm.

const chỉ dành cho người dùng. Nó không tồn tại cho thực thi thực tế.

+2

Không hoàn toàn đúng; nếu đối tượng không, ví dụ: tham chiếu đếm sau đó các rhs có thể cần phải được sửa đổi. –

+3

@OliCharlesworth: Tôi cho rằng nên là thành viên 'có thể thay đổi', vì thường số lượng tham chiếu không phải là một phần của trạng thái quan sát được –

+0

@AndyProwl: đã đồng ý. Tôi chỉ muốn xua tan khẳng định rằng rhs không bao giờ được sửa đổi;) –

10

Điều cuối cùng mà bất kỳ người tiêu dùng nào trong lớp của bạn mong đợi là một nhà xây dựng bản sao đã thay đổi đối tượng đã được sao chép! Vì vậy, bạn nên luôn luôn đánh dấu là const.

2

Nếu trình tạo bản sao không chỉ định tham số của nó là const thì đoạn này sẽ không biên dịch.

const ABC foo; 
ABC bar(foo); 
+0

Hoặc, thậm chí có thể nhiều hơn, không phải điều này: 'ABC bar (some_func_returning_ABC()); ' – Angew

6

Có hai lý do mà const có thể cần thiết ở đây:

  1. Nó đảm bảo rằng bạn không vô tình "thiệt hại" bản gốc khi đưa ra các bản sao - Đây là một điều tốt, bởi vì bạn không thực sự muốn đối tượng ban đầu của bạn được thay đổi khi tạo một bản sao của nó!
  2. Bạn có thể truyền vào một thứ khác ngoài một đối tượng cơ bản - vì hàm tạo tham chiếu, nếu nó không phải là một đối tượng - ví dụ như một biểu thức.

Để minh họa cho trường hợp thứ hai:

class ABC 
    { 
     public: 
      int a; 
      int b; 
     ABC(const ABC &other) 
     { 
     a = other.a; 
     b = other.b; 
     } 
     ABC operator+(const ABC &other) 
     { 
      ABC res; 
      res.a = a + other.a; 
      res.b = b + other.b; 
      return res; 
     } 
    } 

    ... 
    ABC A; 
    a.a = 1; 
    a.b = 2; 
    ABC B(a+a); 

này sẽ không biên dịch nếu các nhà xây dựng là ABC(ABC &other), vì a+a là một đối tượng tạm thời loại ABC. Nhưng nếu đó là ABC(const ABC &other), chúng tôi có thể sử dụng kết quả tạm thời của phép tính và vẫn chuyển nó thành tham chiếu.

5

Như một số câu trả lời khác chỉ ra, một nhà xây dựng bản sao sửa đổi đối số của nó sẽ là một bất ngờ khó chịu. Tuy nhiên, đó không phải là vấn đề duy nhất. Đôi khi các trình tạo bản sao được sử dụng với các đối số là thời gian. (Ví dụ: trả về từ hàm.) Và tham chiếu không const đến thời gian không bay, như được giải thích elsewhere trên SO.

0

Nó không phải là "phải" theo nghĩa kỹ thuật. Chúng tôi thậm chí có con thú như vậy ngay trong tiêu chuẩn, mặc dù it got deprecated. Thực hiện theo các liên kết cho lý do.

Ngữ nghĩa của bản sao mà chúng tôi mong đợi là để nguyên mẫu "không đổi" và cung cấp bản sao tương đương chính xác liên quan đến bạn.

Điều đó được mong đợi bạn sẽ nghĩ hai lần để có một bản sao ctor mà không khác. Nó sẽ làm người dùng ngạc nhiên và có khả năng đưa ra lỗi. Và sự thất vọng và tiếng ồn, chỉ cần cố gắng google cho 'vector của auto_ptr' chỉ để xem số lượng.

Phần còn lại của câu hỏi có thể là "Tôi thề sẽ không chạm vào bản gốc trong quá trình triển khai, nhưng muốn có chữ ký khác". Chữ ký gì? Hãy thử T và T &.

T rút ra vì nó sẽ yêu cầu ctor sao chép có thể sử dụng được và chúng tôi đang thực hiện điều đó. Đệ quy: xem đệ quy.

Lá rời T &. Điều đó thực sự sẽ làm việc cho một vụ kiện. Nhưng chỉ thất bại nếu đối tượng ban đầu của bạn xảy ra để ngồi xung quanh trong một hình thức const, hoặc là tạm thời. Tại sao cản trở trường hợp hợp lý đó không có mưa?

0

Ngoài những giả định cơ bản mà copy constructor không nên thay đổi các trường hợp nguồn, bài viết này trau chuốt vào lý do kỹ thuật thực tế cho việc sử dụng const:

http://www.geeksforgeeks.org/copy-constructor-argument-const/

Cụ thể đó và tôi trích dẫn:

"... trình biên dịch được tạo ra đối tượng tạm thời không thể bị ràng buộc để không const tài liệu tham khảo ..."