Jump to content

Копировать элизию

В на C++ программировании компьютерном исключение копирования относится к методу оптимизации компилятора , который устраняет ненужное копирование объектов .

Стандарт языка C++ обычно позволяет реализациям выполнять любую оптимизацию при условии, что наблюдаемое поведение результирующей программы такое же, как если бы , т. е. притворялось, что программа выполнялась точно так, как того требует стандарт. Помимо этого, стандарт также описывает несколько ситуаций, когда копирование можно исключить, даже если это изменит поведение программы, наиболее распространенной из которых является оптимизация возвращаемого значения (см. ниже ). Другая широко реализованная оптимизация, описанная в стандарте C++ , — это копирование временного объекта типа класса в объект того же типа. [1] [2] В результате инициализация копирования обычно эквивалентна прямой инициализации с точки зрения производительности, но не семантики; для инициализации копирования по-прежнему требуется доступный конструктор копирования . [3] Оптимизацию нельзя применить к временному объекту, привязанному к ссылке.

#include <iostream>int n = 0;struct C {  explicit C(int) {}  C(const C&) { ++n; }  // the copy constructor has a visible side effect};                      // it modifies an object with static storage durationint main() {  C c1(42);      // direct-initialization, calls C::C(int)  C c2 = C(42);  // copy-initialization, calls C::C(const C&)  std::cout << n << std::endl;  // prints 0 if the copy was elided, 1 otherwise}

Согласно стандарту аналогичная оптимизация может быть применена к брошенным и пойманным объектам . [4] [5] но неясно, применяется ли оптимизация как к копии из выброшенного объекта в объект исключения , так и к копии из объекта исключения в объект, объявленный в объявлении исключения предложения catch . Также неясно, применяется ли эта оптимизация только к временным объектам или к именованным объектам. [6] Учитывая следующий исходный код:

#include <iostream>struct C {  C() = default;  C(const C&) { std::cout << "Hello World!\n"; }};void f() {  C c;  throw c;  // copying the named object c into the exception object.}  // It is unclear whether this copy may be elided (omitted).int main() {  try {    f();  } catch (C c) {  // copying the exception object into the temporary in the                   // exception declaration.  }  // It is also unclear whether this copy may be elided (omitted).}

Поэтому соответствующий компилятор должен создать программу , которая выводит «Hello World!» дважды. В версии C++11 стандарта C++ эти проблемы были решены, по существу позволяя исключить как копирование из именованного объекта в объект исключения, так и копирование в объект, объявленный в обработчике исключений. [6]

GCC предоставляет -fno-elide-constructors возможность отключить копирование. Эта опция полезна для наблюдения (или не наблюдения) за эффектами оптимизации возвращаемого значения или других оптимизаций, при которых копии опускаются. Обычно не рекомендуется отключать эту важную оптимизацию.

C++17 обеспечивает «гарантированное исключение копирования», значение prvalue не материализуется до тех пор, пока оно не понадобится, а затем оно создается непосредственно в хранилище конечного пункта назначения. [7]

Оптимизация возвращаемой стоимости

[ редактировать ]

В контексте C++ языка программирования , оптимизация возвращаемого значения ( RVO ) — это оптимизация компилятора , которая включает в себя удаление временного объекта созданного для хранения возвращаемого значения функции . [8] RVO разрешено изменять наблюдаемое поведение результирующей программы по стандарту C++ . [9]

Краткое содержание

[ редактировать ]

В общем, стандарт C++ позволяет компилятору выполнять любую оптимизацию при условии, что результирующий исполняемый файл демонстрирует такое же наблюдаемое поведение , как если бы (то есть делал вид, что) все требования стандарта были выполнены. Это обычно называют « правилом как если бы ». [10] [2] Термин «оптимизация возвращаемого значения» относится к специальному предложению стандарта C++ , которое идет даже дальше, чем правило «как если бы»: реализация может опускать операцию копирования, следующую из оператора return , даже если конструктор копирования имеет побочные эффекты . [1] [2]

В следующем примере показан сценарий, в котором реализация может исключить одну или обе копии, даже если конструктор копирования имеет видимый побочный эффект (печать текста). [1] [2] Первой копией, которую можно удалить, является та, в которой находится безымянный временный объект. C можно скопировать в функцию f значение возвращаемое . Вторая копия, которую можно удалить, — это копия временного объекта, возвращаемого f к obj.

#include <iostream>struct C {  C() = default;  C(const C&) { std::cout << "A copy was made.\n"; }};C f() {  return C();}int main() {  std::cout << "Hello World!\n";  C obj = f();}

В зависимости от компилятора и его настроек результирующая программа может отображать любой из следующих выходных данных:

Hello World!A copy was made.A copy was made.
Hello World!A copy was made.
Hello World!

Возврат объекта встроенного типа из функции обычно практически не требует накладных расходов, поскольку объект обычно помещается в регистр ЦП . Возврат более крупного объекта типа класса может потребовать более дорогостоящего копирования из одной области памяти в другую. Чтобы избежать этого, реализация может создать скрытый объект во фрейме стека вызывающей стороны и передать адрес этого объекта функции. Возвращаемое значение функции затем копируется в скрытый объект. [11] Таким образом, такой код:

struct Data {   char bytes[16]; };Data F() {  Data result = {};  // generate result  return result;}int main() {  Data d = F();}

может сгенерировать код, эквивалентный этому:

struct Data {  char bytes[16];};Data* F(Data* _hiddenAddress) {  Data result = {};  // copy result into hidden object  *_hiddenAddress = result;  return _hiddenAddress;}int main() {  Data _hidden;           // create hidden object  Data d = *F(&_hidden);  // copy the result into d}

что вызывает Data объект, который нужно скопировать дважды.

На ранних этапах развития C++ неспособность языка эффективно возвращать объект типа класса из функции считалась его слабостью. [12] Примерно в 1991 году Уолтер Брайт реализовал метод минимизации копирования, эффективно заменяя скрытый объект и именованный объект внутри функции объектом, используемым для хранения результата: [13]

struct Data {  char bytes[16];};void F(Data* p) {  // generate result directly in *p}int main() {  Data d;  F(&d);}

Брайт реализовал эту оптимизацию в своем компиляторе Zortech C++ . [12] Этот конкретный метод позже был назван «Оптимизация именованного возвращаемого значения» (NRVO), имея в виду тот факт, что копирование именованного объекта исключается. [13]

Поддержка компилятора

[ редактировать ]

Оптимизация возвращаемого значения поддерживается большинством компиляторов. [8] [14] [15] Однако могут возникнуть обстоятельства, когда компилятор не сможет выполнить оптимизацию. Одним из распространенных случаев является ситуация, когда функция может возвращать разные именованные объекты в зависимости от пути выполнения: [11] [14] [16]

#include <string>std::string F(bool cond = false) {  std::string first("first");  std::string second("second");  // the function may return one of two named objects  // depending on its argument. RVO might not be applied  return cond ? first : second;}int main() {  std::string result = F();}
[ редактировать ]
  1. ^ Jump up to: а б с ИСО / МЭК (2003). ISO/IEC 14882:2003(E): Языки программирования – C++ §12.8 Копирование объектов класса [class.copy], параграф. 15
  2. ^ Jump up to: а б с д ИСО / МЭК (2003). «§ 12.8 Копирование объектов класса [class.copy]». ISO/IEC 14882:2003(E): Языки программирования — C++ (PDF) . пункт. 15. Архивировано из оригинала (PDF) 10 апреля 2023 г. Проверено 26 февраля 2024 г.
  3. ^ Саттер, Херб (2001). Еще более исключительный C++ . Аддисон-Уэсли.
  4. ^ ИСО / МЭК (2003). ISO/IEC 14882:2003(E): Языки программирования – C++ §15.1 Выдача исключения [Exception.throw], параграф. 5
  5. ^ ИСО / МЭК (2003). ISO/IEC 14882:2003(E): Языки программирования – C++ §15.3 Обработка исключения [Exception.handle], параграф. 17
  6. ^ Jump up to: а б «Отчеты о дефектах стандартного базового языка C++» . РГ21 . Проверено 27 марта 2009 г.
  7. ^ https://en.cppreference.com/w/cpp/language/copy_elision
  8. ^ Jump up to: а б Мейерс, Скотт (1995). Более эффективный C++ . Аддисон-Уэсли. ISBN  9780201633719 .
  9. ^ Александреску, Андрей (01 февраля 2003 г.). «Перемещение конструкторов» . Журнал доктора Добба . Проверено 25 марта 2009 г.
  10. ^ ИСО / МЭК (2003). ISO/IEC 14882:2003(E): Языки программирования – C++ §1.9 Выполнение программы [intro.execution], параграф. 1
  11. ^ Jump up to: а б Булька, Дов; Дэвид Мэйхью (2000). Эффективный С++ . Аддисон-Уэсли. ISBN  0-201-37950-3 .
  12. ^ Jump up to: а б Липпман, Стэн (3 февраля 2004 г.). «Оптимизация возвращаемого значения имени» . Майкрософт . Проверено 23 марта 2009 г.
  13. ^ Jump up to: а б «Глоссарий языка программирования D 2.0» . Цифровой Марс . Проверено 23 марта 2009 г.
  14. ^ Jump up to: а б Шукри, Айман Б. (октябрь 2005 г.). «Оптимизация именованного возвращаемого значения в Visual C++ 2005» . Майкрософт . Проверено 20 марта 2009 г.
  15. ^ «Параметры, управляющие диалектом C++» . ССЗ . 17 марта 2001 г. Проверено 20 января 2018 г.
  16. ^ Хиннант, Ховард; и др. (10 сентября 2002 г.). «N1377: Предложение добавить поддержку семантики перемещения в язык C++» . РГ21 . Проверено 25 марта 2009 г.
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 1c1b3dd532314563c4daccfe094d1bbc__1710265200
URL1:https://arc.ask3.ru/arc/aa/1c/bc/1c1b3dd532314563c4daccfe094d1bbc.html
Заголовок, (Title) документа по адресу, URL1:
Copy elision - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)