在C ++复制删除期间如何管理内存?

问题描述

#include <iostream>

using namespace std;

class A
{
public :
    A()
    {
        cout<<"constructor is called"<<endl;
    }
    
    ~A()
    {
        cout<<"destructor is called"<<endl;
    }
    
    A(const A &s)
    {
        cout<<"copy constructor is called"<<endl;
    }
};

A beta()
{
    A a;
    cout<<"mem location a : "<<&a<<endl;
    return a;
}

int main(int argc,char** argv) {
    A b = beta();
    cout<<"mem location b : "<<&b<<endl;
    return 0;
}

上面的程序生成以下输出

constructor is called
mem location a : 0x7ffc12bdaf77
mem location b : 0x7ffc12bdaf77
destructor is called

据我了解,由于复制省略或返回值优化,仅创建了一个A实例,而没有为 A a A b 创建2个实例。 但是从内存角度看上面的程序,对象a在函数beta的堆栈激活记录或堆栈空间内,并且内存位置为0x7ffc12bdaf77 。当它从beta返回时,复制省略使对象b与对象a相同,而不是复制它。因此,现在 b的地址也为0x7ffc12bdaf77 。我无法理解i f b仍然是main函数的局部变量,并且存在于其堆栈空间内,它如何在main的堆栈空间之外占用内存?

解决方法

在Microsoft x64调用约定中,将以隐藏指针作为 <form class="user-registration-form user-registration-form-login login" method="post"> <div class="ur-form-row"> <div class="ur-form-grid"> <p class="user-registration-form-row user-registration-form-row--wide form-row form-row-wide"> <label for="username">Username or email address <span class="required">*</span></label> <input placeholder="" type="text" class="user-registration-Input user-registration-Input--text input-text" name="username" id="username" value="" /> </p> <p class="user-registration-form-row user-registration-form-row--wide form-row form-row-wide"> <label for="password">Password <span class="required">*</span></label> <span class="password-input-group"> <input placeholder="" class="user-registration-Input user-registration-Input--text input-text" type="password" name="password" id="password" /> </span> </p> <p class="form-row"> <input type="hidden" id="user-registration-login-nonce" name="user-registration-login-nonce" value="00cebd1a11" /><input type="hidden" name="_wp_http_referer" value="/my-account/" /> <input type="submit" class="user-registration-Button button" name="login" value="Login" /> <input type="hidden" name="redirect" value="" /> <label class="user-registration-form__label user-registration-form__label-for-checkbox inline"> <input class="user-registration-form__input user-registration-form__input-checkbox" name="rememberme" type="checkbox" id="rememberme" value="forever" /> <span>Remember me</span> </label> </p> <p class="user-registration-LostPassword lost_password"> <a href="http://localhost/my-account/lost-password/">Lost your password?</a> </p> </p> </div> </div> </form> 的第一个参数。该指针包含data scores; length variables $ 16; input variables $ low high score; datalines; Debt -10000 1 55 Debt 1 10000 23 MAX_NA -1 1 500 MAX_NA 1 100 -240 ; data main_data; input ID Debt MAX_NA; datalines; 222554 7584 12 212552 20 0 883123 500 7 913464 -200 -78 ; data end_result; input ID Debt MAX_NA score; datalines; 222554 7584 12 -217 212552 20 0 523 883123 500 7 -185 913464 -200 -78 555 ; 的地址,该地址将位于beta的堆栈帧上。该指针将用于立即在b的堆栈帧上同时创建maina。因此,换句话说,b 不存在于main的堆栈帧中的任何位置;从内存的角度来看,abeta将是等效的。

,

请考虑以下行:A b = beta();。编译器如何实现?

嗯,beta是其他功能。并且beta的返回值为A。因此,有两种方法可以实现此目的。编译器可以使beta为其返回值A分配堆栈空间,但是由于调用者需要使用该返回值,因此可能会出现问题。因此,相反,编译器使调用方为返回值分配堆栈空间。毕竟,调用者确实知道返回值的大小/对齐方式,因此它具有分配该空间所需的一切。

所以让我们去看看后者。这意味着,当编译器调用beta时,它将传入beta的返回值所在的地址。但这也意味着对于此beta的特定调用,编译器可以只给beta的返回值提供与给定b相同的地址。

因此,在此处,我们已将副本从函数的返回值中删除到b中。

因此,当编译器进行编译beta时,它知道调用者将向其提供指向返回值应到达的位置的指针。因此,return a;语句从a变量语义上复制到此返回值对象中。

但是,编译器可以看到整个beta。并且可以看到a变量是局部变量,并且在所有控制路径上都将其返回。因此,编译器无需给a提供单独的堆栈地址,只需将a放在调用方提供的返回值内存中即可。

同样,我们从a中删除了一个副本到返回值中。

,

据我了解,仅创建了一个A实例,而不是2个。

正确。

它如何在main的堆栈空间之外占用内存?

不是。

返回值仅在main调用的堆栈帧中创建。