Tôi đã thấy default
được sử dụng bên cạnh các khai báo hàm trong một lớp. Nó làm gì?
class C {
C(const C&) = default;
C(C&&) = default;
C& operator=(const C&) & = default;
C& operator=(C&&) & = default;
virtual ~C() { }
};
Tôi đã thấy default
được sử dụng bên cạnh các khai báo hàm trong một lớp. Nó làm gì?
class C {
C(const C&) = default;
C(C&&) = default;
C& operator=(const C&) & = default;
C& operator=(C&&) & = default;
virtual ~C() { }
};
Câu trả lời:
Đây là một tính năng mới của C ++ 11 .
Điều đó có nghĩa là bạn muốn sử dụng phiên bản do trình biên dịch tạo ra, vì vậy bạn không cần chỉ định phần thân.
Bạn cũng có thể sử dụng = delete
để chỉ định rằng bạn không muốn trình biên dịch tự động tạo chức năng đó.
Với sự ra đời của các hàm tạo di chuyển và các toán tử gán chuyển động, các quy tắc khi các phiên bản tự động của các hàm tạo, hàm hủy và toán tử gán được tạo ra đã trở nên khá phức tạp. Sử dụng = default
và = delete
làm cho mọi thứ dễ dàng hơn khi bạn không cần phải nhớ các quy tắc: bạn chỉ cần nói những gì bạn muốn xảy ra.
= delete
mạnh hơn: Có nghĩa là, sử dụng chức năng đó bị cấm, mặc dù nó vẫn tham gia vào độ phân giải quá tải.
Đây là một tính năng C ++ 0x mới cho trình biên dịch tạo phiên bản mặc định của hàm tạo hoặc toán tử gán tương ứng, tức là một tính năng chỉ thực hiện hành động sao chép hoặc di chuyển cho mỗi thành viên. Điều này hữu ích vì hàm tạo di chuyển không phải lúc nào cũng được tạo theo mặc định (ví dụ: nếu bạn có hàm hủy tùy chỉnh), không giống như hàm tạo sao chép (và tương tự như vậy đối với phép gán), nhưng nếu không có gì không tầm thường để viết, thì tốt hơn là để trình biên dịch xử lý nó hơn là đánh vần nó mỗi lần.
Cũng lưu ý rằng một hàm tạo mặc định sẽ không được tạo nếu bạn cung cấp bất kỳ hàm tạo không mặc định nào khác. Nếu bạn vẫn muốn hàm tạo mặc định, bạn có thể sử dụng cú pháp này để trình biên dịch tạo một.
Như một trường hợp sử dụng khác, có một số tình huống trong đó một hàm tạo sao chép sẽ không được tạo hoàn toàn (ví dụ: nếu bạn cung cấp một hàm tạo di chuyển tùy chỉnh). Nếu bạn vẫn muốn phiên bản mặc định, bạn có thể yêu cầu nó với cú pháp này.
Xem Phần 12.8 của tiêu chuẩn để biết chi tiết.
operator new/new[]
, operator delete/delete[]
và quá tải của chúng.
Nó là mới trong C ++ 11, xem ở đây . Nó có thể khá hữu ích nếu bạn đã xác định một hàm tạo, nhưng muốn sử dụng mặc định cho các hàm khác. Pre-C ++ 11 bạn phải xác định tất cả các hàm tạo sau khi bạn đã xác định một hàm, ngay cả khi chúng tương đương với các giá trị mặc định.
Cũng lưu ý rằng trong một số trường hợp nhất định, không thể cung cấp hàm tạo mặc định do người dùng xác định, hoạt động giống như trình biên dịch được tổng hợp theo trình biên dịch mặc định và khởi tạo giá trị . default
cho phép bạn lấy lại hành vi đó
Dự thảo tiêu chuẩn C ++ 17 N4659
https://github.com/cplusplus/draft/blob/master/ con / n4659.pdf 11.4.2 "Các hàm mặc định rõ ràng":
1 Định nghĩa hàm của biểu mẫu:
attribute-specifier-seq opt decl-specifier-seq opt declarator virt-specifier-seq opt = default ;
được gọi là một định nghĩa mặc định rõ ràng. Một chức năng được mặc định rõ ràng sẽ
(1.1) - là một chức năng thành viên đặc biệt,
(1.2) - có cùng loại chức năng được khai báo (ngoại trừ có thể khác nhau về các vòng loại giới thiệu và ngoại trừ trong trường hợp của hàm tạo sao chép hoặc toán tử gán sao chép, loại tham số có thể là tham chiếu tới T-không phải là const, trong đó T là tên của lớp chức năng thành viên) như thể nó đã được khai báo ngầm, và
(1.3) - không có đối số mặc định.
2 Hàm mặc định rõ ràng không được xác định là đã xóa chỉ có thể được khai báo constexpr nếu nó được khai báo ngầm là constexpr. Nếu một hàm được mặc định rõ ràng trong khai báo đầu tiên của nó, thì nó được coi là ngầm định nếu khai báo ngầm sẽ là.
3 Nếu một chức năng được mặc định rõ ràng được khai báo với một bộ xác định noexcept không tạo ra đặc tả ngoại lệ giống như khai báo ngầm (18.4), thì
(3.1) - nếu chức năng được mặc định rõ ràng trong khai báo đầu tiên, nó được định nghĩa là đã xóa;
(3.2) - mặt khác, chương trình không được định hình.
4 [Ví dụ:
struct S { constexpr S() = default; // ill-formed: implicit S() is not constexpr S(int a = 0) = default; // ill-formed: default argument void operator=(const S&) = default; // ill-formed: non-matching return type ~ S() noexcept(false) = default; // deleted: exception specification does not match private: int i; // OK: private copy constructor S(S&); }; S::S(S&) = default; // OK: defines copy constructor
- ví dụ kết thúc]
5 Các hàm được mặc định rõ ràng và các hàm được khai báo ngầm được gọi chung là các hàm mặc định và việc triển khai sẽ cung cấp các định nghĩa ngầm cho chúng (15.1 15.4, 15.8), có nghĩa là xác định chúng là đã bị xóa. Một hàm được cung cấp bởi người dùng nếu nó được khai báo bởi người dùng và không được mặc định hoặc xóa rõ ràng trên khai báo đầu tiên của nó. Hàm được mặc định rõ ràng do người dùng cung cấp (nghĩa là được mặc định rõ ràng sau khi khai báo đầu tiên) được xác định tại điểm mà nó được mặc định rõ ràng; nếu một chức năng như vậy được định nghĩa ngầm là bị xóa, chương trình sẽ không được định dạng. [Lưu ý: Khai báo một hàm như mặc định sau khai báo đầu tiên của nó có thể cung cấp thực thi hiệu quả và định nghĩa ngắn gọn trong khi cho phép giao diện nhị phân ổn định cho cơ sở mã đang phát triển. - lưu ý cuối]
6 [Ví dụ:
struct trivial { trivial() = default; trivial(const trivial&) = default; trivial(trivial&&) = default; trivial& operator=(const trivial&) = default; trivial& operator=(trivial&&) = default; ~ trivial() = default; }; struct nontrivial1 { nontrivial1(); }; nontrivial1::nontrivial1() = default; // not first declaration
- ví dụ kết thúc]
Sau đó, câu hỏi là tất nhiên các chức năng có thể được khai báo ngầm và khi nào điều đó xảy ra, mà tôi đã giải thích tại: