Điều kiện để tự động tạo mặc định / sao chép / di chuyển ctor và sao chép / di chuyển toán tử gán?


127

Tôi muốn làm mới bộ nhớ của mình theo các điều kiện theo đó trình biên dịch thường tự động tạo ra hàm tạo mặc định, hàm tạo sao chép và toán tử gán.

Tôi nhớ lại có một số quy tắc, nhưng tôi không nhớ, và cũng không thể tìm thấy một tài nguyên có uy tín trực tuyến. Có ai giúp được không?

Câu trả lời:


136

Trong phần sau đây, "tự động tạo" có nghĩa là "được khai báo ngầm định là mặc định, nhưng không được xác định là đã xóa". Có những tình huống mà các hàm thành viên đặc biệt được khai báo, nhưng được định nghĩa là bị xóa.

  • Hàm tạo mặc định được tạo tự động nếu không có hàm tạo do người dùng khai báo (§12.1 / 5).
  • Hàm tạo sao chép được tạo tự động nếu không có hàm tạo di chuyển do người dùng khai báo hoặc toán tử chuyển nhượng di chuyển (vì không có hàm tạo di chuyển hoặc toán tử gán chuyển trong C ++ 03, điều này đơn giản hóa thành "luôn luôn" trong C ++ 03) ( §12.8 / 8).
  • Toán tử gán gán sao chép được tạo tự động nếu không có hàm tạo di chuyển do người dùng khai báo hoặc toán tử gán chuyển di chuyển (§12.8 / 19).
  • Hàm hủy được tạo tự động nếu không có hàm hủy do người dùng khai báo (§12.4 / 4).

C ++ 11 và chỉ sau này:

  • Hàm xây dựng di chuyển được tạo tự động nếu không có hàm tạo sao chép do người dùng khai báo, toán tử gán gán hoặc hàm hủy và nếu hàm tạo di chuyển được tạo là hợp lệ (§12.8 / 10).
  • Toán tử gán di chuyển được tạo tự động nếu không có hàm tạo sao chép do người dùng khai báo, toán tử gán gán hoặc hàm hủy và nếu toán tử gán di chuyển được tạo là hợp lệ (ví dụ: nếu không cần gán các thành viên không đổi) (§12.8 / 21).

9
Có một số lượng hủy diệt di truyền? Ý tôi là, tôi đã có một lớp cơ sở với một hàm hủy ảo trống. Nó có ngăn cản việc tạo các constructor di chuyển trong các lớp con không? Nếu câu trả lời là có, nó có giúp ích gì không nếu tôi định nghĩa một hàm tạo di chuyển trong lớp cơ sở?
kamilk

10
Tôi nghĩ rằng bạn nên đề cập có lẽ việc có constcác thành viên trong lớp sẽ ngăn không cho nhà xây dựng được tạo tự động ...
nonsensickle

Có "Có những tình huống trong đó các hàm thành viên đặc biệt được khai báo, nhưng được định nghĩa là đã xóa." tham khảo nơi bạn ví dụ có const hoặc thành viên tham chiếu nơi di chuyển sẽ là không thể? Không, điều đó là không thể, bởi vì có bản sao sẽ được áp dụng.
Towi

Tôi biết rằng nó bị hạn chế để gửi siêu liên kết trong diễn đàn này. Nhưng nó cũng là bài viết tốt - cplusplus.com/articles/y8hv0pDG
bruziuz

Lưu ý, theo tiêu chuẩn, một hàm tạo sao chép mặc định mặc định " không được dùng nếu lớp có toán tử gán sao chép do người dùng khai báo hoặc hàm hủy khai báo do người dùng khai báo " ( 12.8 Sao chép và di chuyển các đối tượng lớp [class.copy] ).
sigy

98

Tôi đã tìm thấy sơ đồ dưới đây rất hữu ích.

Quy tắc C ++ cho các hàm tạo tự động và toán tử gán từ Dính Bits - Trở thành Quy tắc của Anh hùng Không


Xinh đẹp. "Độc lập" đề cập đến điều gì? Độc lập với cái gì?
Towi

8
Sao chép ctor / gán là 'độc lập' với nhau. Nếu bạn viết chỉ một, trình biên dịch sẽ cung cấp cái khác. Ngược lại, nếu bạn cung cấp một ctor di chuyển hoặc một nhiệm vụ di chuyển, trình biên dịch sẽ không cung cấp cái khác.
Marco M ..

Tự hỏi lý do đằng sau các hoạt động sao chép là độc lập. Lý do lịch sử có thể là? hoặc thực tế là bản sao sẽ không sửa đổi mục tiêu của nó nhưng di chuyển thì sao?
RaGa__M

@Explorer_N Có, khả năng tương thích ngược, vì vậy lý do lịch sử. Đó là một lựa chọn thiết kế tồi từ lâu, vì vậy bây giờ cần có các thực tiễn tốt như "quy tắc ba" (xác định cả 3 hoặc không: xây dựng bản sao, toán tử gán sao chép và thường là hàm hủy) để tránh khó tìm lỗi.
atablash

@MarcoM., Theo như tôi đã hiểu, điều kiện "Nếu bạn viết ..." bao gồm hai trường hợp đặt chức năng thành viên đặc biệt thành = delete(rõ ràng) hoặc = default(ít rõ ràng hơn đối với tôi). Tôi có đúng không
Enrico Maria De Angelis

2

Dự thảo tiêu chuẩn C ++ 17 N4659

Để tham khảo tiêu chuẩn chéo nhanh, hãy xem các phần "Khai báo ngầm" của các mục cppreference sau:

Các thông tin tương tự tất nhiên có thể được lấy từ tiêu chuẩn. Ví dụ : dự thảo tiêu chuẩn C ++ 17 N4659 :

15.8.1 "Sao chép / di chuyển các hàm tạo" nói cho trình tạo bản sao:

6 Nếu định nghĩa lớp không khai báo rõ ràng một hàm tạo sao chép, thì một định nghĩa không rõ ràng được khai báo ngầm. Nếu định nghĩa lớp khai báo hàm tạo di chuyển hoặc toán tử gán di chuyển, hàm tạo sao chép được khai báo ngầm định nghĩa là bị xóa; mặt khác, nó được định nghĩa là mặc định (11.4). Trường hợp thứ hai không được dùng nữa nếu lớp có toán tử gán sao chép do người dùng khai báo hoặc hàm hủy do người dùng khai báo.

và đối với nhà xây dựng di chuyển:

8 Nếu định nghĩa của lớp X không khai báo rõ ràng một hàm tạo di chuyển, thì một định nghĩa không rõ ràng sẽ được khai báo ngầm định là mặc định khi và chỉ khi

  • (8.1) - X không có hàm tạo sao chép do người dùng khai báo,

  • (8.2) - X không có toán tử gán sao chép do người dùng khai báo,

  • (8.3) - X không có toán tử gán di chuyển do người dùng khai báo và

  • (8.4) - X không có hàm hủy do người dùng khai báo.

15.8.2 "Sao chép / di chuyển toán tử gán" nói cho gán sao chép:

2 Nếu định nghĩa lớp không khai báo rõ ràng một toán tử gán sao chép, thì một định nghĩa được khai báo ngầm. Nếu định nghĩa lớp khai báo một hàm tạo di chuyển hoặc toán tử gán chuyển động, toán tử gán gán sao chép được khai báo ngầm định nghĩa là bị xóa; mặt khác, nó được định nghĩa là mặc định (11.4). Trường hợp thứ hai không được dùng nữa nếu lớp có hàm tạo sao chép do người dùng khai báo hoặc hàm hủy do người dùng khai báo.

và cho chuyển nhượng di chuyển:

4 Nếu định nghĩa của lớp X không khai báo rõ ràng một toán tử gán di chuyển, thì một định nghĩa sẽ được khai báo ngầm định là mặc định khi và chỉ khi

  • (4.1) - X không có hàm tạo sao chép do người dùng khai báo,
  • (4.2) - X không có hàm tạo di chuyển do người dùng khai báo,
  • (4.3) - X không có toán tử gán sao chép do người dùng khai báo và
  • (4.4) - X không có hàm hủy do người dùng khai báo.

15.4 "Kẻ hủy diệt" nói rằng nó dành cho kẻ hủy diệt:

4 Nếu một lớp không có hàm hủy được khai báo bởi người dùng, thì hàm hủy được mặc định khai báo là mặc định (11.4). Một hàm hủy được khai báo ngầm là một thành viên công khai nội tuyến của lớp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.