Là BÒ basic_string
bị cấm trong C ++ 11 trở lên không?
Về
” Tôi có đúng là C ++ 11 không thừa nhận việc triển khai dựa trên COW của std::string
?
Đúng.
Về
” Nếu vậy, hạn chế này có được nêu rõ ràng ở đâu đó trong tiêu chuẩn mới (ở đâu) không?
Gần như trực tiếp, bởi các yêu cầu về độ phức tạp liên tục đối với một số hoạt động yêu cầusao chép vật lýO ( n ) dữ liệu chuỗi trong quá trình triển khai COW.
Ví dụ, đối với các chức năng thành viên
auto operator[](size_type pos) const -> const_reference;
auto operator[](size_type pos) -> reference;
… Mà trong quá trình triển khai COW sẽ ¹thể kích hoạt sao chép dữ liệu chuỗi để hủy chia sẻ giá trị chuỗi, tiêu chuẩn C ++ 11 yêu cầu
C ++ 11 §21.4.5 / 4 :
”Độ phức tạp: thời gian không đổi.
… Loại trừ việc sao chép dữ liệu như vậy, và do đó, COW.
C ++ 03 được hỗ trợ triển khai COW bởi không có những yêu cầu liên tục phức tạp, và bởi, trong điều kiện hạn chế nhất định, cho phép các cuộc gọi đến operator[]()
, at()
, begin()
, rbegin()
, end()
, hoặc rend()
để tham khảo vô hiệu, con trỏ và lặp đề cập đến các mặt hàng chuỗi, tức là để có thể phải chịu một Sao chép dữ liệu BÒ. Hỗ trợ này đã bị loại bỏ trong C ++ 11.
COW có bị cấm thông qua các quy tắc hủy bỏ hiệu lực C ++ 11 không?
Trong một câu trả lời khác tại thời điểm viết bài được chọn làm giải pháp và được nhiều người ủng hộ và do đó dường như được tin tưởng, nó khẳng định rằng
” Đối với chuỗi COW, việc gọi non- const
operator[]
sẽ yêu cầu tạo một bản sao (và làm mất hiệu lực tham chiếu), điều này không được phép trong đoạn [trích dẫn] ở trên [C ++ 11 §21.4.1 / 6]. Do đó, không còn hợp pháp khi có chuỗi COW trong C ++ 11.
Khẳng định đó không chính xác và gây hiểu lầm theo hai cách chính:
- Nó chỉ ra không chính xác rằng chỉ những người truy cập không phải
const
mặt hàng mới cần kích hoạt sao chép dữ liệu COW.
Nhưng người truy cập const
mục cũng cần kích hoạt sao chép dữ liệu, vì chúng cho phép mã máy khách tạo thành tham chiếu hoặc con trỏ (trong C ++ 11) nó không được phép làm mất hiệu lực sau này thông qua các hoạt động có thể kích hoạt sao chép dữ liệu COW.
- Nó giả định không chính xác rằng việc sao chép dữ liệu COW có thể làm mất hiệu lực tham chiếu.
Nhưng trong một triển khai đúng, việc sao chép dữ liệu COW, việc hủy chia sẻ giá trị chuỗi, được thực hiện tại một điểm trước khi có bất kỳ tham chiếu nào có thể bị vô hiệu.
Để xem cách triển khai COW đúng trong C ++ 11 basic_string
sẽ hoạt động như thế nào , khi các yêu cầu O (1) làm cho điều này không hợp lệ bị bỏ qua, hãy nghĩ về một triển khai trong đó một chuỗi có thể chuyển đổi giữa các chính sách quyền sở hữu. Một cá thể chuỗi bắt đầu với chính sách Có thể chia sẻ. Với chính sách này hoạt động, không thể có tham chiếu mặt hàng bên ngoài. Phiên bản có thể chuyển đổi sang chính sách Unique và nó phải làm như vậy khi một tham chiếu mục có khả năng được tạo, chẳng hạn như với lệnh gọi tới.c_str()
(ít nhất là nếu điều đó tạo ra một con trỏ tới bộ đệm nội bộ). Trong trường hợp chung của nhiều trường hợp chia sẻ quyền sở hữu giá trị, điều này đòi hỏi phải sao chép dữ liệu chuỗi. Sau quá trình chuyển đổi đó sang chính sách Duy nhất, cá thể chỉ có thể chuyển trở lại Có thể chia sẻ bằng một thao tác làm vô hiệu tất cả các tham chiếu, chẳng hạn như chuyển nhượng.
Vì vậy, trong khi kết luận của câu trả lời đó, rằng chuỗi COW bị loại trừ, là đúng, thì lý do được đưa ra là không chính xác và gây hiểu lầm nghiêm trọng.
Tôi nghi ngờ nguyên nhân của sự hiểu lầm này là một lưu ý không chuẩn mực trong phụ lục C của C ++ 11:
C ++ 11 §C.2.11 [diff.cpp03.strings], về §21.3:
Thay đổi : basic_string
các yêu cầu không còn cho phép các chuỗi được tính tham chiếu
Lý do: Sự hợp lệ khác biệt một cách tinh tế với các chuỗi được tính tham chiếu. Thay đổi này quy định hành vi (sic) đối với tiêu chuẩn này.
Ảnh hưởng đến tính năng gốc: Mã C ++ 2003 hợp lệ có thể thực thi khác trong tiêu chuẩn này
Đây là lý do giải thích lý do chính tại sao người ta quyết định loại bỏ hỗ trợ COW đặc biệt C ++ 03. Cơ sở lý do này không phải là cách tiêu chuẩn ngăn cản việc thực hiện COW một cách hiệu quả. Tiêu chuẩn không cho phép COW thông qua các yêu cầu O (1).
Tóm lại, các quy tắc vô hiệu hóa C ++ 11 không loại trừ việc triển khai COW std::basic_string
. Nhưng họ loại trừ một cách triển khai COW kiểu C ++ 03 không hạn chế, hiệu quả hợp lý giống như cách triển khai trong ít nhất một trong các triển khai thư viện tiêu chuẩn của g ++. Hỗ trợ C ++ 03 COW đặc biệt cho phép hiệu quả thực tế, đặc biệt là sử dụng các trình truy cập const
mục, với chi phí là các quy tắc phức tạp, phức tạp để vô hiệu hóa:
C ++ 03 §21.3 / 5 bao gồm hỗ trợ COW “cuộc gọi đầu tiên”:
” Các tham chiếu, con trỏ và trình vòng lặp tham chiếu đến các phần tử của một basic_string
chuỗi có thể bị vô hiệu bởi các cách sử dụng sau của basic_string
đối tượng đó :
- Làm đối số cho các hàm không phải là thành viên swap()
(21.3.7.8), operator>>()
(21.3.7.9) và getline()
(21.3. 7.9).
- Như một lý lẽ để basic_string::swap()
.
- Chức năng gọi điện data()
và c_str()
thành viên.
- Kêu gọi phi const
chức năng thành viên, trừ operator[]()
, at()
, begin()
, rbegin()
, end()
, và rend()
.
- Tiếp theo cho bất kỳ trong những ứng dụng trên ngoại trừ các hình thức insert()
và erase()
đó trở lại vòng lặp, cuộc gọi đầu tiên để phi const
chức năng thành viên operator[]()
, at()
, begin()
, , hoặcrbegin()
,end()
rend()
.
Những quy tắc này phức tạp và tinh vi đến nỗi tôi nghi ngờ nhiều lập trình viên, nếu có, có thể đưa ra một bản tóm tắt chính xác. Tôi không thể.
Điều gì sẽ xảy ra nếu các yêu cầu O (1) bị bỏ qua?
Nếu các yêu cầu về thời gian không đổi trong C ++ 11 đối với ví dụ operator[]
được bỏ qua, thì COW for basic_string
có thể khả thi về mặt kỹ thuật, nhưng khó thực hiện.
Các hoạt động có thể truy cập nội dung của một chuỗi mà không phải sao chép dữ liệu COW bao gồm:
- Kết nối qua
+
.
- Đầu ra thông qua
<<
.
- Sử dụng một
basic_string
đối số làm đối số cho các hàm thư viện tiêu chuẩn.
Cái sau vì thư viện chuẩn được phép dựa trên kiến thức và cấu trúc cụ thể để triển khai.
Ngoài ra, một triển khai có thể cung cấp các chức năng không chuẩn khác nhau để truy cập nội dung chuỗi mà không kích hoạt sao chép dữ liệu COW.
Một yếu tố phức tạp chính là trong C ++ 11, basic_string
quyền truy cập mục phải kích hoạt sao chép dữ liệu (hủy chia sẻ dữ liệu chuỗi) nhưng được yêu cầu không ném , ví dụ C ++ 11 §21.4.5 / 3 “ Throws: Nothing.”. Và vì vậy nó không thể sử dụng phân bổ động thông thường để tạo một bộ đệm mới cho việc sao chép dữ liệu COW. Một cách giải quyết vấn đề này là sử dụng một heap đặc biệt, nơi có thể dự trữ mà không thực sự được cấp phát, và sau đó dự trữ số tiền cần thiết cho mỗi tham chiếu logic đến giá trị chuỗi. Dự trữ và hủy đặt trước trong một đống như vậy có thể là thời gian không đổi, O (1) và phân bổ số tiền mà một người đã đặt trước, có thể bộ nhớ noexcept
. Để tuân thủ các yêu cầu của tiêu chuẩn, với cách tiếp cận này, có vẻ như cần phải có một đống đặc biệt dựa trên đặt trước cho mỗi người phân bổ riêng biệt.
Lưu ý:
¹ Trình truy cập const
mặt hàng kích hoạt sao chép dữ liệu BÒ vì nó cho phép mã khách hàng nhận được tham chiếu hoặc con trỏ đến dữ liệu, mà mã này không được phép làm mất hiệu lực bởi việc sao chép dữ liệu sau đó được kích hoạt bởi ví dụ: trình truy cập không phải const
mặt hàng.