В чем причина исключения копирования в C++?
По какой причине стандарт C++ позволяет (требует) компиляторам оптимизировать вызовы конструктора копирования (в определенных случаях), даже если он может содержать наблюдаемые побочные эффекты?
Если я не ошибаюсь, правило "как будто" уже позволяет компиляторам оптимизировать ненужный код, если полученная программа имитирует наблюдаемое поведение абстрактной машины, определенной в стандарте.
Каковы мотивы создания правила исключения? Разве это не создает несоответствия в языке? Это удобно (или нужно)?
2 ответа
В подавляющем большинстве случаев копия, созданная при возврате, будет бесполезной. В остальное время ожидается, что побочные эффекты конструктора копирования будут отменены уничтожением копии. Вещи как
std::shared_ptr
делать работу с копией, которую можно наблюдать извне, но отменяет ее при уничтожении. Крайне редко конструкция копии объекта имеет побочный эффект, который может быть упущен при копировании. Это стоит того, чтобы избежать снижения производительности в редком случае. Это в принципе никогда не вызывает проблем.
Копирование может означать две разные вещи. "Обязательное исключение копирования" в C++17 - это просто переопределение того, что такое prvalue.
auto foo() { return std::mutex{}; }
Это законно и имеет смысл, потому что внутри функции
std::mutex
еще не "создан", что касается языка. Не будем останавливаться на этом деле.
В других случаях, например,
auto bar()
{
std::vector v{1, 2, 3};
return v;
}
компилятору разрешено исключить копирование / перемещение после проверки того, что семантика копирования / перемещения допустима.
Разве это не создает несоответствия в языке?
Да. Но редко бывает язык, столь зацикленный на согласованности, как C++, исключение копирования выделяется именно потому, что C++ ценит согласованность. Этот компромисс делается ради исключительно большого преимущества: мы не хотим, чтобы люди беспокоились о накладных расходах на производительность при написании функций.
Правило "как если бы" иногда теоретически достаточно для генерации эффективного кода, но на практике оно зачастую чрезвычайно сложно. У компиляторов есть проблемы с оптимизацией в течение длительного времени
delete new int;
тривиально, как это может быть для человека. Мы не хотим ждать, пока оптимизаторы станут идеальными, прежде чем начинать писать функции.