2016-06-24 6 views
3

Я искал this статью о NRVO.понимание вызова конструктора копирования и названная оптимизация возвращаемого значения

class RVO 
    { 
    public: 
    RVO(){ 
      printf("I am in constructor\n"); } 
    RVO(const RVO& c_RVO) { 
      printf("I am in copy constructor\n"); } 
    ~RVO(){ 
      printf("I am in destructor\n"); } 
    int mem_var; 
    }; 
    RVO MyMethod(int i) 
    { 
    RVO rvo; 
    rvo.mem_var = i; 
    return (rvo); 
    } 
    int main() 
    { 
     RVO rvo; 
     rvo=MyMethod(5); 
    } 

Выход следующие на визуальной студии, и это, как я понимаю

I am in constructor  // main rvo construction 
I am in constructor  //MyMethod rvo construction 
I am in copy constructor //temporary created inside MyMethod 
I am in destructor  //Destroying rvo in MyMethod 
I am in destructor  //Destroying temporary in MyMethod 
I am in destructor  //Destroying rvo of main 

Если вместо этого я пишу главным, как

int main() 
{ 
    RVO rvo = MyMethod(5); 
    return 0; 
} 

Выход заключается в следующем, и как это понимается

I am in constructor  //MyMethod rvo construction 
I am in copy constructor //temporary created inside MyMethod 
I am in destructor  //Destroying rvo in MyMethod 
I am in destructor  //Destroying rvo of main 

Почему временная не разрушена в Mymethod во второй версии?

Почему конструктор копирования не вызывается в RVO rvo = MyMethod(5); .I думаю, конструктор копирования должен быть вызван дважды во второй версии, один для временного создается внутри Mymethod, а другой для RVO rvo = MyMethod(5); Я знаю, что некоторые называют могут получать elided.Can кто-то пожалуйста, помощь в объяснении этих вызовов.

EDIT: Использование return rvo вместо return (rvo) изменяет выход как

Первый случай

I am in constructor 
I am in constructor 
I am in destructor 
I am in destructor 

второй случай

I am in constructor 
I am in destructor  

Думаю, когда я удалены скобки, то NRVO умирает . Но меня больше интересует первый вывод, когда нет оптимизации

+0

Есть что-то подозрительное в отношении вывода второго примера. Любой резонирующий компилятор должен применять RVO, поэтому вы не должны получать вызов конструктора копии. –

+0

@ Cheersandhth.-Alf см. Это http://ideone.com/S5Kqn9 –

+0

Удалите круглые скобки вокруг возвращаемого выражения. –

ответ

0

UPDATE: адресация выход обновленной программы, используя return rvo вместо return (rvo);

I am in constructor 
I am in constructor 
I am in destructor 
I am in destructor 

Причина вы видите это в том, что оба объекта (MyMethod::rvo и main::rvo) претерпевают строительство по умолчанию, то последнее назначается как отдельное действие, но вы не регистрируете его.


Вы можете получить гораздо лучшее представление о том, что происходит путем вывода адреса объектов и значения this указателя, как называются функции:

#include <cstdio> 
#include <iostream> 
class RVO 
    { 
    public: 
    RVO(){ 
      printf("%p constructor\n", this); } 
    RVO(const RVO& c_RVO) { 
      printf("%p copy constructor, rhs %p\n", this, &c_RVO); } 
    ~RVO(){ 
      printf("%p destructor\n", this); } 
    int mem_var; 
    }; 
    RVO MyMethod(int i) 
    { 
    RVO rvo; 
    std::cout << "MyMethod::rvo @ " << &rvo << '\n'; 
    rvo.mem_var = i; 
    return (rvo); 
    } 
    int main() 
    { 
     RVO rvo=MyMethod(5); 
     std::cout << "main::rvo @ " << &rvo << '\n'; 
    } 

Выход будет также зависеть от скомпилированы ли вы с оптимизацией; вы ссылаетесь на документацию Microsoft, поэтому, возможно, вы используете компилятор Microsoft - попробуйте cl /O2.

Почему временная не разрушена в Mymethod во второй версии?

Там не было временного - объект в main был непосредственно скопирован. Шагая вас через него:

002AFA4C constructor 
MyMethod::rvo @ 002AFA4C // MyMethod::rvo's constructed 

002AFA70 copy constructor, rhs 002AFA4C // above is copied to 2AFA70 
002AFA4C destructor  // MyMethod::rvo's destructed 
main::rvo @ 002AFA70  // turns out the copy above was directly to main::rvo 
002AFA70 destructor  // main::rvo's destruction 

[комментарий Альф в ниже] «копировать напрямую возведенный» не совсем значимый для меня. Я думаю, что ОП означает РВО локальную переменную

Рассмотрим расширенный выход из первой версии программы (без оптимизации):

002FF890 constructor // we find out this is main::rvo below 
002FF864 constructor // this one's MyMethod::rvo 
MyMethod::rvo @ 002FF864 
002FF888 copy constructor, rhs 002FF864 // 2FF888 is some temporary 
002FF864 destructor // there goes MyMethod::rvo 
002FF888 destructor // there goes the temporary 
main::rvo @ 002FF890 
002FF890 destructor // and finally main::rvo 

Если мы привязываем, что еще в к выходу OP и аннотации ...

I am in constructor  // main rvo construction 
I am in constructor  //MyMethod rvo construction 
I am in copy constructor //temporary created inside MyMethod 
I am in destructor  //Destroying rvo in MyMethod 
I am in destructor  //Destroying temporary in MyMethod 
I am in destructor  //Destroying rvo of main 

ОП (правильно) относится к объекту, созданному для копирования, в качестве временного. Когда я говорю о второй версии программы «Там не было временного - объект в основном был напрямую построен по копиям». - Я имею в виду, что в первой программе, которую мы анализировали непосредственно выше, нет никакого временного эквивалента, а вместо этого это main::rvo, которая копируется из MyMethod::rvo.

+0

«прямое копирование» не имеет для меня никакого значения. Я думаю, что OP означает локальную переменную 'rvo'. –

+1

@ Cheersandhth.-Alf: Я прохожу через него в последней редакции - надеюсь, что это понятно. Приветствия. –

+0

@TonyD Вывод для второго случая, о котором вы упоминали, показывает, что была сделана некоторая оптимизация. правильно? Я запустил второй случай с отключением оптимизации, даже тогда я получаю тот же результат (с некоторой оптимизацией). Если оптимизация отключена, должны быть два вызова конструктора экземпляра. Правильно? –

0

Первый вызов дескриптора - из-за дескрипции rvo в главном. Созданный объект должен быть удален. Это не копирование, которое сделано, это построение копии.