Є корова basic_string
заборонено на C ++ 11 та пізніших версіях?
Стосовно
" Чи я правильний, що C ++ 11 не допускає реалізацію на основі COW std::string
?
Так.
Стосовно
" Якщо так, то це обмеження прямо вказано десь у новому стандарті (де)?
Майже безпосередньо, вимогами постійної складності для ряду операцій, які потребували б O ( n ) фізичного копіювання рядкових даних при реалізації програми COW.
Наприклад, для функцій-членів
auto operator[](size_type pos) const -> const_reference;
auto operator[](size_type pos) -> reference;
… Що в реалізації програми COW призведе до triggerзапуску копіювання рядкових даних, щоб розділити значення рядка, стандарт C ++ 11 вимагає
C ++ 11 §21.4.5 / 4 :
” Складність: постійне час.
… Що виключає таке копіювання даних, а значить, і COW.
C ++ 03 підтримуються реалізації корови НЕ маючи ці вимоги постійної складності, і, за певних обмежувальних умов, що дозволяє дзвонити на operator[]()
, at()
, begin()
, rbegin()
, end()
, або rend()
про визнання недійсних посилань, покажчики і Ітератор зі посиланням на строкових елементи, тобто , можливо , понесе Копіювання даних COW. Ця підтримка була видалена в C ++ 11.
Чи забороняється КР також через правила недійсності C ++ 11?
В іншій відповіді, яка на момент написання вибору обрана як рішення, і яка сильно оцінена і тому, мабуть, вважається, вона стверджує, що
" Для рядка COW для виклику non- const
operator[]
потрібно буде зробити копію (та недійсні посилання), що заборонено [цитованим] пунктом вище [C ++ 11 §21.4.1 / 6]. Отже, більше не законно мати рядок COW в C ++ 11.
Це твердження є невірним та оманливим двома основними способами:
- Це неправильно вказує на те, що
const
копіювати дані COW потрібно лише непропозиційним постачальникам.
Але також const
постачальникам елементів потрібно запустити копіювання даних, оскільки вони дозволяють клієнтському коду формувати посилання або покажчики, на які (в C ++ 11) пізніше не можна визнати недійсними через операції, які можуть викликати копіювання даних COW.
- Це неправильно передбачає, що копіювання даних COW може призвести до недійсності посилань.
Але при правильній реалізації копіювання даних COW, не розподіляючи значення рядка, робиться в момент, перш ніж з’являться будь-які посилання, які можуть бути визнані недійсними.
Щоб побачити, як працює правильна реалізація C ++ 11 COW basic_string
, коли вимоги O (1), які роблять це недійсним, ігноруються, подумайте про реалізацію, де рядок може перемикатися між політикою власності. Екземпляр рядка починається з політики Sharable. Якщо ця політика активна, не може бути зовнішніх посилань на елементи. Екземпляр може переходити до унікальної політики, і він повинен це робити, коли потенційно створюється посилання на елемент, наприклад, із закликом до .c_str()
(принаймні, якщо це створює вказівник на внутрішній буфер). У загальному випадку для кількох примірників, що ділять право власності на значення, це тягне за собою копіювання рядкових даних. Після цього переходу до унікальної політики екземпляр може переходити назад до Sharable лише операцією, яка скасовує всі посилання, наприклад, призначення.
Отже, хоча висновок цієї відповіді про те, що нитки КОР виключені, є правильним, пропоновані міркування невірні та сильно оманливі.
Я підозрюю, що причиною цього непорозуміння є ненормативна примітка у додатку С ++ 11 до додатка C:
C ++ 11 §C.2.11 [diff.cpp03.strings], про §21.3:
Зміна : basic_string
вимоги більше не дозволяють посилатися на рядки рядків
Обгрунтування: Недійсне визнання суттєво відрізняється від рядків, що рахуються посиланням. Ця зміна регулює поведінку (sic) цього Міжнародного стандарту.
Вплив на оригінальну функцію: Дійсний код C ++ 2003 може виконуватися по-різному в цьому Міжнародному стандарті
Тут обґрунтування пояснює головне, чому хтось вирішив усунути спеціальну підтримку COW C ++ 03. Таке обґрунтування, чому , не полягає в тому , як стандарт ефективно забороняє впровадження КОР. Стандарт забороняє КРС через вимоги O (1).
Коротше кажучи, правила інвалідизації C ++ 11 не виключають впровадження програми COW std::basic_string
. Але вони виключають досить ефективну необмежену реалізацію COW у стилі C ++ 03, наприклад, у щонайменше одній із стандартних реалізацій бібліотеки g ++. Спеціальна підтримка COW C ++ 03 COW дозволила досягти практичної ефективності, зокрема, використовуючи const
аксесуари для предметів, ціною складних правил щодо визнання недійсними:
C ++ 03 §21.3 / 5, який включає підтримку
КРУ "для першого дзвінка":
” Посилання, покажчики та ітератори, що посилаються на елементи basic_string
послідовності, можуть бути визнані недійсними внаслідок таких застосувань цього basic_string
об’єкта:
- Як аргумент для swap()
нечленуючих функцій (21.3.7.8), operator>>()
(21.3.7.9) та getline()
(21.3. 7.9).
- Як аргумент до basic_string::swap()
.
- Функції виклику data()
та c_str()
учасника.
- Виклик непро- const
функцій - членів, за винятком operator[]()
, at()
, begin()
, rbegin()
, end()
, і rend()
.
- Після будь-якої з вищевказаних цілей , за винятком форм insert()
і erase()
які повертають ітератори, перший виклик , що не є const
функції - членів operator[]()
, at()
, begin()
, rbegin()
,end()
, або rend()
.
Ці правила є настільки складними і тонкими, що я сумніваюсь, що багато програмістів, якщо такі є, могли б дати точний підсумок. Я не можу.
Що робити, якщо вимоги O (1) не дотримуються?
Якщо вимоги постійного часу C ++ 11 щодо, наприклад, operator[]
не враховуються, то КОР basic_string
може бути технічно здійсненним, але важким у виконанні.
Операції, які могли отримати доступ до вмісту рядка без копіювання даних COW, включають:
- З'єднання через
+
.
- Вихід через
<<
.
- Використання в
basic_string
якості аргументу стандартних функцій бібліотеки.
Останнє тому, що стандартній бібліотеці дозволено покладатися на впровадження конкретних знань та конструкцій.
Крім того, реалізація може запропонувати різні нестандартні функції доступу до рядкового вмісту без ініціювання копіювання даних COW.
Основним ускладнюючим фактором є те, що в C ++ 11 basic_string
елемент доступу повинен викликати копіювання даних (не поділяючи рядкові дані), але він не повинен викидати , наприклад, C ++ 11 §21.4.5 / 3 " Кидає: нічого". І тому він не може використовувати звичайний динамічний розподіл для створення нового буфера для копіювання даних COW. Одним із способів цього є використання спеціальної купи, де можна зарезервувати без фактичного розподілу, а потім резервувати необхідну кількість для кожної логічної посилання на значення рядка. Зарезервувати та зняти резервування в такій купі може бути постійний час, O (1), і виділити суму, яку вже забронювали, може бути пам'ять noexcept
. Для того, щоб відповідати вимогам стандарту, при такому підході, мабуть, знадобиться одна така спеціальна купа на основі резервування на окремий розподільник.
Примітки:
access const
Аксесуар товару запускає копіювання даних COW, оскільки він дозволяє клієнтському коду отримати посилання або вказівник на дані, які забороняється визнати недійсними при пізнішому копіюванні даних, ініційованому, наприклад, немеханічним const
доступом.