Toán tử new () hoạt động khác đi khi toán tử xóa () bị xóa tùy thuộc vào sự tồn tại của hàm tạo mặc định


17

Tạo một đối tượng mới của lớp C với toán tử new () gây ra lỗi ở đây:

class C
{
public:
    C() {}
    virtual ~C() {}

    void operator delete(void*) = delete;
};


int main()
{
    C* c = new C;
}

với C2280: 'void C::operator delete(void *)': function was explicitly deleted

Nhưng khi tôi thay thế C() {} bằng C() = default; hoặc loại bỏ dòng để trình biên dịch chèn một hàm tạo mặc định (mà tôi tin là có tác dụng tương tự = default), mã sẽ biên dịch và chạy.

Sự khác biệt giữa hàm tạo mặc định do trình biên dịch tạo và hàm tạo mặc định do người dùng định nghĩa làm cho điều này xảy ra là gì?

Tôi có một số gợi ý trong bài đăng này , nhưng lớp C ở đây (không có hàm tạo do người dùng cung cấp) không tầm thường vì hàm hủy là ảo, phải không?

Được biên dịch với Visual Studio mới nhất, c ++ 17.


3
Không chắc chắn, nhưng tôi nghĩ rằng sự khác biệt là hàm tạo mặc định lànoexcept
Sebastian Redl

1
Không thể sao chép bằng g ++. Chẩn đoán tương tự liên quan đến operator delete()việc liệu constructor được viết thủ công hay được tạo ngầm. Điều này phù hợp với mong đợi của tôi - vì một ngoại lệ có thể bị ném bởi newbiểu thức, trình biên dịch cần truy cập operator delete().
Peter

@SebastianRedl bạn nói đúng, thêm noexceptsẽ làm cho mã được biên dịch, nhưng làm thế nào ...?
yeshjho

1
@Peter Ngoại lệ chỉ có thể được ném bởi nhà xây dựng, vì vậy nếu đó là noexceptnhư SebastianRedl đã đề cập, thì operator deletekhông cần phải bao gồm một cuộc gọi . Ngoài ra g ++ không phàn nàn nếu hàm hủy là ảo. Mặt khác, nó luôn luôn biên dịch, ngay cả khi hàm tạo đang ném.
quả óc chó

@LeDYoM Liên kết của bạn là về phân tích địa chỉ IP, dường như không liên quan đến câu hỏi. Bạn đã đăng một liên kết sai?
LF

Câu trả lời:


17

Sự khác biệt giữa hàm tạo mặc định do trình biên dịch tạo và hàm tạo mặc định do người dùng định nghĩa làm cho điều này xảy ra là gì?

newbiểu thức gọi tương ứng operator newvà sau đó gọi hàm tạo. Nếu hàm tạo ném một newbiểu thức ngoại lệ phải hoàn tác hiệu ứng của operator new(để tránh rò rỉ bộ nhớ) bằng cách gọi tương ứng operator delete. Nếu newbiểu thức sau bị xóa thì không thể gọi nó là kết quả trong trình biên dịch error: use of deleted function 'static void C::operator delete(void*)'.

Một noexceptconstructor không thể ném một ngoại lệ, do đó, tương ứng operator deletelà không cần thiết vì nó sẽ không được gọi bởi một newbiểu thức. Một defaultconstructor của một lớp tầm thường cũng là một noexceptconstructor. Sự hiện diện của một hàm hủy ảo yêu cầu operator deletekhông bị xóa vì hàm hủy vô hướng đặc biệt (một chi tiết thực hiện để cho phép deletebiểu thức thông qua con trỏ lớp cơ sở) gọi operator delete.

Nó dường như không được chỉ định bởi tiêu chuẩn C ++ cho dù trình biên dịch phải yêu cầu operator deletekhông bị xóa ngay cả khi nó không thể được gọi bằng newbiểu thức. gccTuy nhiên, dường như không được gọi tương ứng operator deletetrong newbiểu hiện ở tất cả nếu nó là deleted (gửi một báo cáo lỗ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.