C++中静态方法的局部变量范围

Scope of variable local to static method in C++

本文关键字:局部变量 范围 静态方法 C++      更新时间:2023-10-16

我试图使用私有构造函数创建一个对象的实例。这种方法正确吗?

#include <iostream> 
using namespace std; 
class A{
int y;
A(int y=2):y(y){};
public:
A(const A &obj){
cout<<"copy Cotr is called"<<endl;
this->y=obj.y;
}
int* addr(){
int *a=&y;
return a;
}
static A create(int y1=2){
class A a(y1);
cout<<&a<<endl;
return a;
}
void print(){
cout<<y<<endl;
}
};
int main(){
A o1=A::create(1);
A o2=A::create(3);
cout<<&o1<<" "<<&o2<<endl;
return 0;
}

输出为:

0x7ffd20d2f280
0x7ffd20d2f284
0x7ffd20d2f280 0x7ffd20d2f284

在上面的代码中,我无法理解几点:

  1. create()返回一个值,所以在A o1=A::create(1);中发生的赋值期间,应该调用复制构造函数,但事实并非如此。 为什么?
  2. 这是一些未定义的行为,因为在create()main()中创建的对象的地址是相同的,并且create()中的对象是本地的,并且在函数结束后超出范围。
create
  1. (( 返回一个值,因此在A o1=A::create(1);中发生的赋值期间,应该调用复制构造函数,但事实并非如此。

您有复制消除(演示(,这是标准允许的优化。

对象直接在最终位置构造,不进行复制/移动。

在 C++17 中,一些复制省略甚至是强制性的。(在你的情况下有一半(。

  1. 这是一些未定义的行为,因为在 create(( 和 main(( 中创建的对象的地址是相同的,并且 create(( 中的对象是本地的,并且在函数结束后超出范围。

使用复制省略,由于对象是直接在最终位置构造的,因此确实只有一个地址,就好像create的局部变量是来自main的地址一样。

这个:

A a = x();

与此不同:

A a;
a = x();

在第二种情况下,您有副本,在第一种情况下,您没有。

为了回答你的第二个问题,在create((中创建的对象是本地的,但随后它被复制回调用者(实际上是移动的(。由于堆栈帧相同,因此本地地址相同。但是当它被复制时,你有两个不同的对象。

感谢您的所有答案。深入研究它,现在回答我自己的问题。

对于有学问的人:

这是第 17 C++中复制省略的主要实例。

答案结束了。对于仍然不明白的人:

此方法没有错误,并且不显示任何未定义的行为。如今,大多数编译器都使用C++11或C++17,它与复制省略(复制省略(很好地集成在一起。

create(( 返回一个值,因此在赋值期间发生在 A o1=A::create(1(;,应该调用复制构造函数,但它不是。为什么?

不调用复制构造函数,因为返回类型是 prvalue(纯右值(,编译器优化程序的方式是将返回值直接创建到存储中,否则函数的返回值将被复制或移动到该存储中。因此,实际上不会发生移动或复制,因此不会调用移动/复制构造函数。即使在create()结束后,也不会调用析构函数。

这是一些未定义的行为,作为所创建对象的地址吗 在 create(( 和 main(( 中是相同的,而 create(( 中的对象是本地的 并在函数结束后超出范围。

因此,即使在函数create()结束后,对象也不会被推出范围,或者不会调用该对象的析构函数。因为对象不是在create()而是在main()本身中创建的。它不是一个未定义的行为,而是C++的一个主要好处,因为不需要声明或调用不必要的指针和函数。在这里,NRVO发生。

  • 在 return 语句中,当操作数是 具有自动存储持续时间的非易失性对象,不是 函数参数或 catch 子句参数,属于 与函数返回的类类型相同(忽略 CV 限定( 类型。这种复制省略的变体被称为NRVO,"命名返回 价值优化"。