Проблемы с продлением жизни c ++ - PullRequest
4 голосов
/ 25 июня 2019

Я пытался понять семантику продления времени жизни временных объектов c ++.Я пытался смоделировать простую ситуацию и был немного удивлен.

Ниже я предоставляю свой код.

#include <iostream>

struct C
{
    C(const int new_a) { a = new_a; };

    int a = 0;
};

C return_num()
{
    C num(20);

    std::cout << "From func(): num = " << num.a << ", by adress: " << &num.a << std::endl;

    return num;
}

void pass_num(const C& num)
{
    std::cout << "From func(): num = " << num.a << ", by adress: " << &num.a << std::endl;
}

int main()
{
    std::cout << "\nLifetime extention:" << std::endl;
    {
        const C& ext_num = return_num();

        std::cout << "From main(): num = " << ext_num.a << ", by adress: " << &ext_num.a << std::endl;
    }

    std::cout << "\nPassing by reference:" << std::endl;
    {
        C num(20);

        std::cout << "From main(): num = " << num.a << ", by adress: " << &num.a << std::endl;

        pass_num(num);
    }
}

Вот главный вопрос: return_num() с любопытством работает с моей точки зрения, потому что я ожидал, что адрес переменной, которыйЯ пытаюсь вывести в main, будет так же, как внутренне в return_num().Не могли бы вы объяснить, почему это не так?

Например, в pass_num() выходной адрес совпадает с внешним адресом, который я получил в main.

Вот пример вывода:

Продолжительность жизни:
Из func (): num = 20, по адресу: 0x7fff44fc8b4c
Из main (): num = 20, по адресу: 0x7fff44fc8b70

Передача по ссылке:
Из main (): num = 20, по адресу: 0x7fff44fc8b6c
Из func (): num = 20, по адресу: 0x7fff44fc8b6c

Ответы [ 3 ]

2 голосов
/ 25 июня 2019

Перемещение конструкторов обычно «крадет» ресурсы, содержащиеся в аргументе (например, указатели на динамически размещаемые объекты, файловые дескрипторы, сокеты TCP, потоки ввода-вывода, запущенные потоки и т. Д.), Вместо того, чтобы делать их копии, и оставляют аргумент в каком-то действительном, но в остальном неопределенном состоянии.

См. Конструктор перемещения

Я изменил ниже в вашем коде, и я надеюсь, что он работает, как ожидалось. Я изменил int a на int* a

#include <iostream>

class C
{
   public:
   int *a;
   C( int new_a) 
   { 
      a = new int();
      *a = new_a;
   };
   C(const C& rhs) { std::cout << "Copy " << std::endl; this->a = rhs.a; }
   C(C&& rhs):a(std::move(rhs.a)) 
   {
      std::cout << "Move!!" <<"Address resource a " << &(*a) << ", Address of 
      resource rhs.a" << &(*rhs.a) << std::endl; rhs.a = nullptr;
      std::cout << "Value of a:: " << *a << std::endl;
   }  

  };

  C return_num()
  {
     C num(20);

     std::cout << "From return_num(): num = " << *num.a << ", Address of resource a : 
     "<< &(*num.a)<< std::endl;
    return (std::move(num));
  }

  void pass_num(const C& num)
  {
     std::cout << "From pass_num(): num = " << *num.a << ", by adress: " << &num.a << 
     std::endl;
  }

  int main()
  {
      std::cout << "\nLifetime extention:" << std::endl;
      {
         const C& ext_num = return_num();

         std::cout << "From main() 1 : num = " << *(ext_num.a) << ", by resource 
         adress: " << &(*ext_num.a) << std::endl;
      }

      std::cout << "\nPassing by reference:" << std::endl;
      {
         C num(20);

         std::cout << "From main() 2 : num = " << *num.a << ", by adress: " << &num.a 
         << std::endl;

         pass_num(num);
       }
       return 0;
    }

Приведенный выше код выдает следующие выходные данные:

Lifetime extention:
From return_num(): num = 20, Address of resource a : 0x7fffeca99280
Move!!Address resource a 0x7fffeca99280, Address of resource rhs.a0x7fffeca99280
Value of a:: 20
From main() 1 : num = 20, by resource adress: 0x7fffeca99280

Passing by reference:
From main() 2 : num = 20, by adress: 0x7ffff466f388
From pass_num(): num = 20, by adress: 0x7ffff466f388

Надеюсь, это поможет!

1 голос
/ 25 июня 2019

Представьте себе эту функцию:

int getNumber(){
    int num = 10;

    return num;
}

Эта функция не возвращает num как объект, она возвращает его безымянную копию (если хотите, r-значение) с тем же значением. Следовательно, он имеет другой адрес.

То же самое происходит с вашей return_num функцией.

0 голосов
/ 25 июня 2019

Я подозреваю, что получение адреса члена препятствует оптимизации, поскольку компилятор не знает, как справляться со всеми возможными крайними случаями. Исключение взятия адреса члена делает работу оптимизации.

#include <iostream>

struct C
{
    C(const int new_a) { a = new_a; };

    int a = 0;
    struct C* t = this;
};

C return_num()
{
    C num(20);

    std::cout << "From func(): num = " << num.a << ", by adress: " << num.t << std::endl;

    return num;
}

void pass_num(const C& num)
{
    std::cout << "From func(): num = " << num.a << ", by adress: " << num.t << std::endl;
}

int main()
{
    std::cout << "\nLifetime extention:" << std::endl;
    {
        const C& ext_num = return_num();

        std::cout << "From main(): num = " << ext_num.a << ", by adress: " << ext_num.t << std::endl;
    }

    std::cout << "\nPassing by reference:" << std::endl;
    {
        C num(20);

        std::cout << "From main(): num = " << num.a << ", by adress: " << num.t << std::endl;

        pass_num(num);
    }
}

Продолжительность жизни:
Из функции (): число = 20, по адресу: 0x7ffd61f48a50
Из main (): число = 20, по адресу: 0x7ffd61f48a50

Передача по ссылке:
Из main (): число = 20, по адресу: 0x7ffd61f48a90
Из функции (): число = 20, по адресу: 0x7ffd61f48a90

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...