2010-02-21 27 views
13

Ý nghĩa chính xác của cụm từ "như thể" trong tiêu chuẩn là gì và nó hoạt động như thế nào khi người dùng có thể sửa đổi các phần riêng lẻ của hành vi."như thể" trong tiêu chuẩn ngôn ngữ

Câu hỏi đặt ra là liên quan đến tiêu chuẩn C++ khi nói về phiên bản chưa phát hành của operator new. 18.4.1.1/7 đọc (tôi nhấn mạnh):

Đây là phiên bản nothrow của nhà khai thác lợi nhuận mới một con trỏ được như thể mua từ các phiên bản bình thường.

Sự hiểu biết của tôi là "như thể" không yêu cầu triển khai cụ thể miễn là hành vi là phù hợp. Vì vậy, nếu operator new được thực hiện như thế này (tôi biết đây không phải là một việc thực hiện phù hợp vì không có vòng lặp hoặc sử dụng các new_handler; nhưng tôi rút ngắn mà tập trung vào vấn đề của tôi):

// NOTE - not fully compliant - for illustration purposes only. 
void *operator new(std::size_t s) 
{ 
    void *p = malloc(s); 
    if (p == 0) 
     throw std::bad_alloc(); 
    return p; 
} 

Sau đó, nó sẽ hợp pháp để viết phiên bản không giống như thế này:

// NOTE - not fully compliant - for illustration purposes only. 
void *operator new(std::size_t s, const std::nothrow_t &nt) 
{ 
    return malloc(s); 
} 

Nhưng giả sử chương trình thay thế operator new để sử dụng một số cấp phát khác. Liệu "như thể" có nghĩa là trình biên dịch phải tự động thay đổi hành vi của phiên bản không dùng để sử dụng cấp phát khác này? Nhà phát triển có bắt buộc phải thay thế cả phiên bản thuần tuý và không phải không?

+0

http://www.gotw.ca/publications/mill15.htm http://www.gotw.ca/publications/mill16.htm –

+2

Bản nháp mới nhất của C++ 0x đã thay đổi từ ngữ: "This nothrow phiên bản của toán tử new trả về một con trỏ thu được như thể có được từ phiên bản thông thường (có thể thay thế). Và hành vi mặc định đã thay đổi thành "Toán tử cuộc gọi mới (kích thước). Nếu cuộc gọi trả về bình thường, trả về kết quả của cuộc gọi đó. Nếu không, trả về một con trỏ rỗng." –

Trả lời

7

Từ 1.9 "thực hiện Chương trình:

triển khai phù hợp được yêu cầu phải thi đua (chỉ) các hành vi quan sát của máy trừu tượng

và trong một chú thích thông tin:

Quy định này đôi khi được gọi nguyên tắc “as-if”, bởi vì việc triển khai là miễn phí để bỏ qua bất kỳ yêu cầu nào của Tiêu chuẩn này miễn là kết quả là như yêu cầu đã được tuân theo, có thể được xác định từ hành vi quan sát của chương trình. instan ce, một thực hiện thực tế không cần đánh giá một phần của một biểu thức nếu nó có thể suy ra rằng giá trị của nó không được sử dụng và không có tác dụng phụ nào ảnh hưởng đến hành vi quan sát được của chương trình được tạo ra.

Tiêu chuẩn đặc biệt lưu ý rằng yêu cầu "as-if" là ràng buộc trên phiên bản thay thế của phiên bản không phát hành operator new(). Tuy nhiên, khi tôi đọc nó, yêu cầu đó sẽ rơi vào lập trình viên ghi đè operator new() không phải trình biên dịch. Mặt trái của trách nhiệm này là tôi nghĩ tiêu chuẩn khá nhiều đòi hỏi việc triển khai mặc định số operator new() được cung cấp bởi thư viện phải làm điều gì đó dọc theo các dòng gọi là ném new trong thử/bắt và trả về 0 nếu std::bad_alloc bị bắt.

Trường hợp quy tắc "như thể" có thể tham gia ở đây là nếu trình biên dịch/liên kết/bất kỳ thông minh nào đủ để hiểu rằng khi mặc định ném new() đang được sử dụng, mặc định không ném new() có thể mất các phím tắt, nhưng nếu mặc định ném new() bị ghi đè, mặc định không ném new() sẽ phải hành động khác nhau. Tôi chắc chắn đây là kỹ thuật có thể cho một thực hiện (ngay cả khi bạn có thể không thể hiện nó trong tiêu chuẩn C + +). Tôi sẽ ngạc nhiên nếu có bao giờ một thực hiện đã làm điều này.

Tôi có thể đọc quá nhiều yêu cầu, nhưng tôi nghĩ đó là điều có thể suy ra.

+0

Tôi không biết tại sao phiên bản đầu tiên của câu trả lời lại nói về hành vi bắt buộc của 'toán tử delete()' vì câu hỏi của bạn không hỏi gì về điều đó. Ngủ quá ít đêm qua hay gì đó. –

+0

về nhận xét của bạn bắt đầu bằng "mặt lật ...", có gì khác trong tiêu chuẩn có thể yêu cầu toán tử mặc định 'khai báo mới' để gọi toán tử' toán tử mới'? –

+0

Tôi không chắc chắn có bất cứ điều gì khác - những gì tôi đã cố gắng để vượt qua là tôi nghĩ rằng điều này ngăn chặn mặc định nothrow 'new()' từ lấy một phím tắt gọi 'malloc()' (hoặc bất cứ điều gì mặc định ném ' new() 'gọi trực tiếp –

2

Nếu thay đổi trong phân bổ trong operator new tạo sự khác biệt quan sát được về hành vi của chương trình C++ tuân thủ thì có thể yêu cầu thay đổi trong việc thực hiện phiên bản no-throw. Cụ thể nếu operator delete chỉ dự kiến ​​các khối được phân bổ bởi người cấp phát mới thì không ném mới phải thay đổi.

Đọc của tôi là sử dụng như thể cho phép thực hiện như của bạn khi người dùng không ghi đè tiêu chuẩn operator new. Ngay khi có, việc triển khai không được sử dụng malloc dựa trên no-throwoperator new và phải gọi cho người dùng tuyên bố phiên bản rõ ràng hoặc ít nhất là sử dụng lại đủ phiên bản được người dùng khai báo rằng chương trình tuân thủ không thể cho biết điều này là không Cách phiên bản no-throw đã được triển khai.

+0

Nếu tôi hiểu chính xác, bạn đề nghị đó là trách nhiệm của trình biên dịch để đảm bảo tính thống nhất giữa nhà điều hành toàn cầu mới và toàn cầu không có gì mới khi người dùng chỉ thay thế một trong số họ. Đó có thể là một gánh nặng cho trình biên dịch, đặc biệt nếu nó phải "sử dụng lại đủ phiên bản được người dùng khai báo". Nếu đó là ý định, có lẽ tiêu chuẩn nên đã quy định rằng nhà điều hành toàn cầu mới được thực hiện trong điều kiện của nothrow mới và không thể được thay thế - người dùng sẽ chỉ được phép ghi đè lên nothrow toàn cầu mới. – Dan

+0

một trong những người không phải chỉ cần 'try {...}' các cuộc gọi đến các nhà điều hành bình thường mới để ngăn chặn trường hợp ngoại lệ từ thoát, tôi nghĩ. Tuy nhiên, điều đó có nghĩa là người mới bình thường không thể gọi cái mới không phải là mới. Kỳ dị. :) –

+0

@Dan: đó là cách khác xung quanh - tiêu chuẩn mạnh mẽ cho thấy rằng không có mới được thực hiện trong điều khoản của ném mới. Tôi không nghĩ rằng có bất kỳ ý định rằng nó nên được bất kỳ cách nào khác, mặc dù nếu không được thay thế thì có tối ưu hóa rõ ràng của nothrow. Charles's "hoặc ít nhất" chỉ là chỉ ra rằng có thể là một thực hiện * có thể * wriggle ra khỏi điều này với một số footwork ưa thích. Thực tế là bước chân ưa thích này là rất khó khăn không phải là một lỗ hổng trong tiêu chuẩn, vì đây là một cái gì đó mà một thực hiện có lẽ sẽ không bao giờ muốn làm. Chỉ cần gọi người dùng mới ném. –

0

Nhà phát triển nên thay thế cả phiên bản thuần và không phát hành. Hãy xem số article này trên GOTW.

Giả định của tôi là tiêu chuẩn đặt các yêu cầu về triển khai mặc định của trình biên dịch (và thời gian chạy). Vì vậy, "như thể" bạn trích dẫn có nghĩa là để thông báo cho nhà cung cấp trình biên dịch rằng việc triển khai mặc định của các phương thức đó phải đáp ứng các tiêu chí được chỉ định. Nếu một nhà phát triển chọn ghi đè chỉ một phiên bản của toán tử mới, tôi không nghĩ đó là trách nhiệm của trình biên dịch để làm cho tất cả các phiên bản khác của toán tử mới tuân thủ. Đó là trách nhiệm của nhà phát triển. Nhưng đó là tất cả các ý kiến ​​của tôi, tôi không có spec spec vào lúc này để xem những gì nó nói trong vấn đề phía trước.

+1

@Dan - bài viết của GOTW nói cụ thể về việc cung cấp một bộ hoàn chỉnh các thay thế cho ** toán tử ** lớp mới cụ thể mới. Tôi tin rằng vấn đề Herb Sutter quan tâm là nếu bạn ghi đè lên toán tử lớp cụ thể mới, bạn sẽ ẩn toán tử nothrow mới trừ khi bạn cũng ghi đè lên nó. –

+0

Điểm tốt, tôi nhớ rằng bạn đã hỏi về các nhà khai thác toàn cầu mới. Điểm cuối cùng trước bản tóm tắt có thể có liên quan đến câu hỏi của bạn: Sutter gợi ý rằng việc phát triển toàn cầu mới phải đảm bảo ngữ nghĩa nhất quán với ngữ nghĩa mới. – Dan

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