Временный объект и конструктор копирования [закрыто]

Вопрос или проблема

У меня есть 3 связанных вопроса
Q1


CLass_A ob1 = CLass_A(); 
//так **временный объект** вызовет пустой конструктор
// я ожидал, что также будет вызван конструктор копирования, чтобы передать
// временный объект в ob1

//как это
CLass_A ob0;
CLass_A ob1 = ob0;
здесь будет вызван копирующий

ТАКЖЕ это также не вызовет конструктор копирования
ПОЧЕМУ???

#include <iostream> 
class A {
 public:
    A(){std::cout<<"ПУСТО";}
    A(const A &C){std::cout<<"Копировать";}
 };
class B {
A a;
  public:
    B(int x):a(A()){}//<<<<<<<<<<<<<<<<<<<//я не могу представить, как это не вызывает конструктор копирования!!!!!
 };
int main() {
     B b(10);
}

Q2
В большинстве операторов return в функциях создается временный объект для хранения возвращаемого значения??
например:


Class_A func(){  | int func(){      |   char func(){
lass_A obj1;     |  int obj1;       |   char obj1
//некод       |   //некод       |    //некод 
return obj1;     |    return obj1;  |    return obj1;
}                |    }             |    }

Q3

Существует, возможно, 5 ситуаций, в которых возникает **Конструктор копирования**.

Вызывает ли оптимизация возврата значения (RVO) отключение конструктора копирования при известных типах из 5
или это случайный процесс, КАК:
это отключает “**возврат объекта по значению в функции **”, а другое отключает конструктор копирования при “передаче объекта в функцию по значению
что я имею в виду: это случайно, и зависит от ОС или есть одна-две ситуации, когда (RVO) отключает их в большинстве ОС или компиляторах, и эти ситуации известны

спасибо большое

я описал, что я попробовал, что я ожидал, что произойдет
с вопросом

Ответ или решение

Ответ на вопросы о временных объектах и конструкторах копирования

Ваши вопросы касаются поведения временных объектов, конструкторов копирования и оптимизаций компиляторов, и я постараюсь подробно ответить на них.

Вопрос 1: Вызов конструктора копирования

  1. Временный объект и его копирование:
    В следующем коде:

    Class_A ob1 = Class_A(); // Вызов пустого конструктора

    Компилятор создаёт временный объект Class_A(), и предполагается, что этот временный объект будет скопирован в ob1. Однако, в большинстве современных компиляторов будет использована оптимизация перемещения или elision (оптимизация исключения) , что означает, что временный объект будет напрямую инициализировать ob1, без вызова конструктора копирования.

    В случае:

    Class_A ob0;
    Class_A ob1 = ob0; // Здесь будет вызван конструктор копирования

    Конструктор копирования будет вызван, так как передается существующий объект, а не временный.

  2. Конструктор копирования внутри класса:
    В следующем коде, который вы представили:

    #include <iostream> 
    class A {
    public:
       A() {std::cout << "EMPTY";}
       A(const A &C) {std::cout << "COPY";}
    };
    
    class B {
       A a;
    public:
       B(int x): a(A()) {} // Здесь не вызывается конструктор копирования
    };
    
    int main() {
       B b(10);
    }

    Здесь происходит "передача временного объекта", но поскольку A инициализируется непосредственно в списке инициализации B, компилятор опять же может использовать оптимизацию перемещения и избежать вызова конструктора копирования.

Вопрос 2: Временные объекты в возвращаемых значениях

Да, на практике, когда функция возвращает объект по значению, компилятор может создать временный объект для хранения возвращаемого значения. Однако, благодаря оптимизации, такой объект может быть либо перемещен, либо уничтожен сразу после возврата. Например:

Class_A func() {
    Class_A obj1; // Создание объекта
    return obj1;  // Оптимизация может не вызвать конструктор копирования.
}

Вопрос 3: Оптимизация возврата значения (RVO) и ее влияние на конструктор копирования

Оптимизация возврата значения (RVO) действительно уменьшает или устраняет необходимость в вызове конструктора копирования в определённых ситуациях. Она работает в следующих случаях:

  • Возврат временного объекта из функции.
  • Инициализация объектов, которые являются результатами функций.

Однако RVO может не выполняться всегда и зависит от нескольких факторов:

  1. Компилятор: Разные компиляторы могут реализовывать RVO по-разному. Кроме того, использование флагов оптимизации влияет на поведение.
  2. Сложность функции: Если функция возвращает сложный объект или у неё разные пути возврата, RVO может не применяться.
  3. Контекст вызова: Если объект передается в функцию по ссылке или указателю, то RVO не применяется.

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

Если у вас есть дополнительные вопросы или вы хотите разобраться в чем-то конкретном, не стесняйтесь спрашивать!

Оцените материал
Добавить комментарий

Капча загружается...