2014-10-29 13 views
5

Tôi biết rằng có khá ít câu hỏi C++ (và câu trả lời ở đây trên SO) nói rằng không cần kiểm tra giá trị trả về của biểu thức mới thuần túy cho null, vì đồng bằng mới - biểu hiện cho biết thất bại bằng cách ném ngoại lệ. Về cơ bản họ nói rằng biểu thức mới đơn giản không bao giờ trả về null. (Theo "biểu thức mới thuần túy", tôi có nghĩa là một biểu thức mới không phải là nothrow một).Toán tử do người dùng định nghĩa mới trả về con trỏ rỗng

Tuy nhiên, mặc dù điều này trông giống như một câu hỏi rất cơ bản, tôi đột nhiên nhận ra rằng tôi không hiểu những giả định cụ thể mà họ đưa ra (nếu có) khi họ đưa ra câu trả lời đó. Cụ thể, tôi tự hỏi liệu tôi có cho phép quá tải dạng đồng bằng cơ bản là ::operator new để luôn trả về con trỏ null hay không, và do đó, tất cả các biểu thức mới thuần túy sử dụng toán tử đó sẽ trả về con trỏ null.

Theo đặc tả ngôn ngữ, nếu ::operator new của tôi được khai báo là không ném, khi đó tôi có thể/sẽ cho biết lỗi cấp phát bộ nhớ bằng cách trả về con trỏ rỗng. Vì vậy, hãy thực hiện điều đó

void *operator new(size_t s) throw() { 
    return 0; 
} 

int main() { 
    int *i = new int; 
} 

Trong các thử nghiệm của tôi, biểu thức mới ở trên sẽ trả về thành công con trỏ rỗng. Vì vậy, tôi có vi phạm bất kỳ quy tắc nào trong đoạn mã trên hay không? Việc khai báo số ::operator new là không hợp lệ có đúng không?

Và nếu mã ở trên là tốt, thì tôi cho rằng khi ai đó nói rằng "không bao giờ trả về con trỏ rỗng" mới, chúng làm điều đó theo giả định rằng phiên bản tiêu chuẩn do thư viện cung cấp ::operator new chưa được thay thế. Giả định đó có đúng không?

+0

Có một khía cạnh khác trong cuộc thảo luận này - ngay cả khi tiêu chuẩn cho phép bạn trả về 'nullptr' /' 0' như bạn đã nói, các thư viện chuẩn có cần xử lý '0' không? Tôi muốn đặt cược họ không - và triển khai không - vì vậy nó sẽ là * không thực tế * để viết một chương trình với một toán tử ':: new' trở về 0. Ví dụ: 20.8.9.1/4 yêu cầu 'std :: allocate :: allocate' ném' std :: bad_alloc' nếu lưu trữ không thể nhận được - nó sẽ (thường redundantly) kiểm tra null, hoặc tin tưởng ':: operator new' để ném? –

+0

Phiên bản không phải là phiên bản mới của 'mới' có yêu cầu chữ ký khác không? toán tử 'void * new (std :: size_t size);' không thể trả về một con trỏ null, nó phải ném trong trường hợp lỗi ngay cả khi nó được định nghĩa lại. – user657267

+0

Thư viện chuẩn sẽ sử dụng ':: new T' để xây dựng tiêu chuẩn và' :: new (static_cast (get_allocator() (1)) T' cho vị trí, và các biểu mẫu này luôn gọi hàm phân bổ ném (bất kể là đã được thay thế) –

Trả lời

1

Các nhà khai thác bạn có thể thay thế như sau

[replacement.functions]

(2.1) — operator new(std::size_t) 
(2.2) — operator new(std::size_t, const std::nothrow_t&) 
(2.3) — operator new[](std::size_t) 
(2.4) — operator new[](std::size_t, const std::nothrow_t&) 
(2.5) — operator delete(void*) 
(2.6) — operator delete(void*, const std::nothrow_t&) 

void *operator new(size_t s) throw() là không hợp lệ, nó để ném trong trường hợp lỗi

[new.delete .single]

void* operator new(std::size_t size); 

3 Hành vi bắt buộc: Trả lại không null con trỏ đến phù hợp được sắp xếp bộ nhớ (3.7.4) hoặc người khác ném một ngoại lệ bad_alloc. Yêu cầu này là ràng buộc trên một phiên bản thay thế của chức năng này.

Tuy nhiên, bạn có thể thay thế an toàn quá tải không noexcept quá tải với chức năng luôn trả về giá trị rỗng, vì ai gọi những quá tải này phải biết hành vi này và kiểm tra giá trị trả lại tương ứng. Rõ ràng là họ sẽ không được gọi là trừ khi thẻ nothrow được thông qua, tức là int* i = new (std::nothrow) int;

void* operator new(std::size_t size, const std::nothrow_t&) noexcept; 

7 hành vi bắt buộc: Return một con trỏ null để canh lề phù hợp lưu trữ (3.7.4), nếu không trả về một con trỏ null. Phiên bản nothrow này của operator new trả về một con trỏ có được như được mua từ phiên bản thông thường (có thể thay thế).Yêu cầu này là ràng buộc trên một phiên bản thay thế của chức năng này.

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