tại sao xóa rõ ràng hàm tạo?


93

Khi nào / tại sao tôi muốn xóa phương thức khởi tạo của mình một cách rõ ràng? Giả sử lý do là để ngăn chặn việc sử dụng nó, tại sao không chỉ làm cho nó private?

class Foo
{ 
  public: 
    Foo() = delete; 
};

14
Nó khá tuyệt vời = default, thậm chí không phải lớp nào cũng có thể sử dụng nó, và cá nhân tôi thích thấy Sử dụng hàm đã xóa hơn. trên Chức năng là riêng tư. Trước đây khẳng định rõ ràng "Điều này không có nghĩa là được sử dụng." Nếu bất cứ điều gì xuất hiện từ đó, lớp không thể sử dụng nó thực sự tạo ra sự khác biệt về ngữ nghĩa.
chris

15
Thành thật mà nói, tôi nghĩ rằng mọi người đang bắt đầu trở nên trầm trọng hơn với những phiếu bầu sát sao. Tôi không thấy cách này không mang tính xây dựng.
Luchian Grigore

4
@LuchianGrigore: Đồng ý. Tôi đã tự hỏi tại sao cộng đồng lại trở nên cứng nhắc hơn nhiều. Tôi không thấy vấn đề.
Ed S.

11
Vì tôi hiếm khi sử dụng C ++ 11, điều này đối với tôi nhiều thông tin hơn OP thậm chí có thể nhận ra. Tôi thậm chí không biết bạn có thể gắn thẻ một hàm tạo cho delete. Cả câu hỏi và câu trả lời của Luchian đều dễ dàng được coi là mang tính xây dựng. Bất cứ ai không hiểu những điểm tốt hơn của C ++ 11 nhưng sẽ cần sớm nhận được điều gì đó từ cả hai.
WhozCraig

Câu trả lời:


87

Làm thế nào về:

//deleted constructor
class Foo
{ 
  public: 
    Foo() = delete;     
  public:
    static void foo();
};

void Foo::foo()
{
   Foo f;    //illegal
}

đấu với

//private constructor
class Foo
{ 
  private: 
    Foo() {}     
  public:
    static void foo();
};

void Foo::foo()
{
   Foo f;    //legal
}

Về cơ bản chúng là những thứ khác nhau. privatecho bạn biết rằng chỉ các thành viên của lớp mới có thể gọi phương thức đó hoặc truy cập vào biến đó (hoặc tất nhiên là bạn bè). Trong trường hợp này, việc một staticphương thức của lớp đó (hoặc bất kỳ thành viên nào khác) gọi một phương thức privatekhởi tạo của một lớp là hợp pháp. Điều này không áp dụng cho các hàm tạo đã xóa.

Mẫu ở đây .


3
Bạn không cần khai báo Foo (), nếu bạn khai báo Foo (int). Foo () sẽ không được tạo và do đó Foo f vẫn không hợp lệ. Vì vậy, ví dụ của bạn không hiển thị trường hợp cho hàm tạo bị xóa. Tự mình xem - Ideone.com/mogiIF
đánh dấu

1
@mark Tôi đã viết 2 hàm tạo để chứng minh quan điểm. Tôi sẽ chỉnh sửa để mọi người rõ ràng.
Luchian Grigore

1
Tôi hiểu sự khác biệt, tôi chỉ không hiểu giá trị gia tăng của câu lệnh xóa nói chung và cho một hàm tạo nói riêng. Rốt cuộc, tôi có thể chỉ định một phương thức khởi tạo mặc định riêng mà không cần phần thân. Sau đó, mã cũng không thành công, chỉ trong quá trình liên kết. Tôi có thể thấy rằng việc xóa thể hiện ý định một cách rõ ràng hơn, nhưng đó là về nó.
đánh dấu

11
@mark Có, đó sẽ là cách hoạt động của C ++ 98. Nhưng IMHO, truyền đạt ý định một cách rõ ràng thực sự là một điều rất quan trọng trong lập trình nói chung. Trong trường hợp này, một số người đọc có thể nhìn thấy một hàm tạo không xác định riêng và cho rằng đó là tình cờ và chỉ cần thêm định nghĩa cho nó, đặc biệt nếu định nghĩa này tầm thường như một hàm tạo mặc định (Vâng, có một nhận xét sẽ giúp ích, nhưng chúng tôi muốn trình biên dịch hơn -thực thi hơn nhận xét-thực thi). Bằng cách làm cho ý định của chúng tôi rõ ràng hơn, chúng tôi cũng nhận được một thông báo lỗi tốt hơn nhiều cho biết "đã xóa rõ ràng" thay vì "tham chiếu không xác định".
mpark

2
Tôi thành thật không hiểu làm thế nào điều này trả lời câu hỏi chính. Câu hỏi trong tiêu đề và câu hỏi đầu tiên của OP trong bài là: Khi nào / tại sao tôi muốn xóa phương thức khởi tạo của mình một cách rõ ràng?
Alexander Bolinsky

11

tại sao xóa rõ ràng hàm tạo?

Một lý do khác:
Tôi sử dụng deletekhi tôi muốn đảm bảo rằng một lớp được gọi bằng bộ khởi tạo. Tôi coi đó là một cách rất thanh lịch để đạt được điều này mà không cần kiểm tra thời gian chạy.

Trình biên dịch C ++ thực hiện việc kiểm tra này cho bạn.

class Foo
{
   public:
       Foo() = delete;
       Foo(int bar) : m_bar(bar) {};
   private:
       int m_bar;
}

Mã này - rất đơn giản - đảm bảo rằng không có sự khởi tạo như thế này:Foo foo;


12
Khai báo đã xóa là không cần thiết ở đây. Nó sẽ tự động bị xóa với bất kỳ constructor dùng cung cấp
Mike Lui

5
Để làm rõ nhận xét của @MikeLui, khai báo đã xóa là không cần thiết đối với trình biên dịch . Có rất nhiều trường hợp khi mã như thế này nên được đưa vào để khai báo ý định cho các lập trình viên khác .
Jeff G

Cùng với việc khai báo ý định của bạn, nó tạo ra một nơi rõ ràng để ghi lại lý do của bạn cho việc xóa nó trong giao diện công khai và ngoài ra, lỗi trình biên dịch sẽ là một cái gì đó ngắn gọn như "sử dụng chức năng đã xóa". Nếu Foocó nhiều hàm tạo, không phải là mặc định, thì Foo foo;sẽ gây ra lỗi lâu hơn nữa khi liệt kê tất cả các hàm tạo được xác định ngầm, được bảo vệ và riêng mà nó không khớp.
sigma

Tôi vẫn không hiểu cách dòng bổ sung với khai báo hàm tạo từ khóa wich "= delete" khai báo ý định về ý tưởng "không có hàm tạo mặc định" tốt hơn so với ... chỉ không có hàm tạo mặc định? Ví dụ: Tôi không muốn khai báo biến "a" trong mã của mình - tốt hơn là viết "// int a; // không cần xác định biến a" hay chỉ viết không có gì về biến này trong mã?
Ezh

2

Tôi đã gặp các ctors mặc định được khai báo là 'đã xóa' trong mã nguồn của LLVM (trong AlignOf.h chẳng hạn). Các mẫu lớp được liên kết thường nằm trong một không gian tên đặc biệt được gọi là 'llvm :: detail'. Toàn bộ mục đích ở đó tôi nghĩ là họ chỉ coi lớp đó như một lớp trợ giúp. Họ không bao giờ có ý định tạo chúng; chỉ để sử dụng chúng trong ngữ cảnh của các mẫu lớp khác với một số thủ thuật lập trình siêu mẫu chạy trong thời gian biên dịch.

Ví dụ. có mẫu lớp AlignmentCalcImpl này chỉ được sử dụng trong một mẫu lớp khác được gọi là AlignOf làm tham số cho toán tử sizeof (.). Biểu thức đó có thể được đánh giá trong thời gian biên dịch; và không cần khởi tạo mẫu -> vậy tại sao không khai báo xóa ctor mặc định để thể hiện ý định này.

Nhưng đó chỉ là giả định của tôi.

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.