我试图理解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
答案 0 :(得分:2)
移动构造函数通常会“窃取”参数所拥有的资源(例如,指向动态分配的对象的指针,文件描述符,TCP套接字,I / O流,运行线程等),而不是复制它们并留下该参数处于某种有效但不确定的状态。
我在您的代码中更改了以下内容,希望它能按预期运行。我将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 :(得分:1)
想象一下这个功能:
int getNumber(){
int num = 10;
return num;
}
此函数不会将num
作为对象返回,它会返回具有相同值的未命名副本(如果有,则为r值)。因此,它具有不同的地址。
return_num
函数也会发生同样的事情。
答案 2 :(得分:-1)
我怀疑采用成员地址会抑制优化,因为编译器不知道如何处理所有可能的边缘情况。消除占用成员的地址即可优化工作。
.tolist()
终身扩展:
从func():num = 20,按地址:0x7ffd61f48a50
从main():num = 20,按地址:0x7ffd61f48a50通过引用传递:
从main():num = 20,按地址:0x7ffd61f48a90
来自func():num = 20,按地址:0x7ffd61f48a90