2015-03-26 15 views
16

Các quy tắc để tự động tạo các hàm di chuyển đặc biệt (hàm tạo và toán tử gán) trong C++ 11 xác định rằng không có khai báo nào. Logic có lẽ là, nếu bạn cần phải làm một cái gì đó đặc biệt trong sự hủy diệt, một động thái có thể không an toàn.C++ 11 destructors ảo và tự động tạo các chức năng di chuyển đặc biệt

Tuy nhiên, đối với các cuộc gọi destructor đúng trong đa hình, cần khai báo lớp hủy của lớp cơ sở là ảo (nếu không xóa một thể hiện của lớp con thông qua con trỏ của lớp cơ sở của nó sẽ không đúng chuỗi hủy).

Tôi giả sử, sau đó, ngay cả một destructor trống sẽ ngăn trình biên dịch tự động tạo ra một chức năng di chuyển đặc biệt. Như trong:

class Base { 
    virtual ~Base() { } 
}; 

Bạn có thể, tuy nhiên, mặc định destructor, như trong:

class Base { 
    virtual ~Base() = default; 
} 

Vì vậy, câu hỏi 1: Điều này sẽ cho phép trình biên dịch để tự động tạo ra các chức năng di chuyển đặc biệt không?

Có sự cố với trình phá hủy mặc định rõ ràng. Trong ít nhất là trường hợp của GCC 4.8.2, chữ ký được thay đổi hoàn toàn thành noexcept. Như trong:

class Base { 
    virtual ~Base() = default; // compiler changes to: 
    // virtual ~Base() noexcept; 
} 

Trong khi tôi không có vấn đề với noexcept trong một destructor, điều này sẽ phá vỡ các "khách hàng" đoạn mã sau:

class Sub : public Base { 
    virtual ~Sub(); // this declaration is now "looser" because of no noexcept 
} 

Vì vậy, câu hỏi 2 là hơn vào vấn đề: là có một cách để cho phép tự động tạo ra các hàm di chuyển đặc biệt trong C++ 11 và cho phép các chuỗi hàm hủy phù hợp với các lớp con (như được mô tả ở trên), tất cả mà không phá vỡ lớp con ("client")?

+1

Tại sao '~ Sub' lỏng hơn? Các trình phá hủy không có các đặc tả ngoại lệ mặc định là 'noexcept'. – Pradhan

+0

Câu hỏi dường như được xác định rõ ràng, nhưng không quan tâm, bạn có ví dụ về lý do tại sao điều này có thể cần thiết không? Điều này có vẻ giống như một hỗn hợp kỳ lạ về giá trị và ngữ nghĩa tham chiếu. Dường như với tôi như trong trường hợp bạn muốn sử dụng di chuyển (hoặc thậm chí sao chép), bạn sẽ không muốn hành vi đa hình. Và hơn thế nữa, bản sao mặc định hoặc di chuyển chắc chắn sẽ không có bất kỳ hành vi đa hình nào. – tahsmith

+0

@tahsmith mục đích là để làm lại các lớp cơ sở theo cách mà chúng và các lớp con của chúng có thể tận dụng các ngữ nghĩa di chuyển mà không phá vỡ các lớp con. – notlesh

Trả lời

16
  1. Không, trình phá hủy mặc định vẫn được coi là do người dùng xác định, do đó nó sẽ ngăn chặn việc tạo hoạt động di chuyển. Cũng khai báo các thao tác di chuyển default -ed để làm cho trình biên dịch tạo ra chúng.

  2. Bạn chỉ cần khai báo các hoạt động di chuyển là default-được đặt trong lớp cơ sở. Trong lớp dẫn xuất, hàm hủy sẽ không được người dùng định nghĩa nữa (trừ khi bạn nói một cách rõ ràng), vì vậy các thao tác di chuyển sẽ không bị xóa.

Vì vậy, những gì tôi muốn làm là như sau:

class Base 
{ 
    virtual ~Base() = default; 
    Base(Base&&) = default; 
    Base& operator=(Base&&) = default; 
    // probably need to think about copy operations also, as the move disables them 
    Base(const Base&) = default; 
    Base& operator=(const Base&) = default; 
}; 

tôi khuyên bạn nên nói chuyện này bởi người đã đóng góp có lẽ là nhất đối với ngữ nghĩa di chuyển: http://www.slideshare.net/ripplelabs/howard-hinnant-accu2014

Hoặc, nếu bạn có thể đặt tay lên, bạn nên đọc mục Mục 17: Hiểu được việc tạo thành viên chức năng đặc biệt từ cuốn sách tuyệt vời của Scott Meyers Hiệu quả hiện đại C++. Vấn đề này được giải thích một cách xuất sắc.

PS: Tôi nghĩ bạn nên suy nghĩ thêm một chút về các lớp cơ sở của mình. Hầu hết thời gian, bạn nên sử dụng các lớp trừu tượng, do đó sẽ không cần sao chép/di chuyển các phiên bản của chúng.

PSS: Tôi nghĩ rằng bằng cách hủy mặc định được đánh dấu noexcept trong C++ 11/14, vì vậy không rõ ràng xác định nó không nên gây ra bất kỳ vấn đề:

nhà xây dựng Kế thừa và mặc định ngầm-tuyên bố constructors , các nhà xây dựng sao chép, di chuyển các nhà xây dựng, các nhà khai thác, các toán tử gán, toán tử di chuyển gán đều là noexcept (true) theo mặc định, trừ khi chúng được yêu cầu gọi hàm không nhận dạng (sai). là noexcept (sai).

+0

Cảm ơn, tôi nghĩ rằng điều này giải quyết vấn đề (và trả lời các câu hỏi). Tôi đã thực sự đọc mục 17 trong cuốn sách của Scott khi tôi đưa ra câu hỏi này :) – notlesh

+0

@stephelton vui vì nó đã giúp. Về đặc tả "looser nothrow", tôi nghĩ rằng tôi đã gặp phải điều này trước đây (g ++ 4.8.x), nó là một vấn đề trình biên dịch, sẽ cố gắng tìm liên kết và đăng nó ở đây – vsoftco

+2

@stephelton tìm thấy nó, xem tại đây: http : //stackoverflow.com/questions/11497252/default-destructor-nothrow – vsoftco

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