简体   繁体   English

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

[英]Scope of variable local to static method in C++

I was trying to create an instance of an object with private constructor.我试图用私有构造函数创建一个对象的实例。 Is this method correct?这个方法正确吗?

#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;
}

The output is:输出是:

0x7ffd20d2f280
0x7ffd20d2f284
0x7ffd20d2f280 0x7ffd20d2f284

In the above code, I fail to understand few points:在上面的代码中,我不明白几点:

  1. create() returns a value, so during assignment which take place in A o1=A::create(1); create()返回一个值,因此在A o1=A::create(1);发生的赋值期间A o1=A::create(1); , copy constructor should be called but it isn't. , 复制构造函数应该被调用,但它不是。 why?为什么?
  2. Is this some undefined behavior as the address of the object created in create() and in main() are same and the object in create() is local and goes out of scope after the function ends.这是一些未定义的行为,因为在create()main()create()的对象的地址相同,并且create()的对象是本地的并且在函数结束后超出范围。

This:这个:

A a = x();

is different than this:与此不同:

A a;
a = x();

In the second case you have a copy, in the first you don't.在第二种情况下你有一个副本,在第一种情况下你没有。

To answer your second question, the object created in create() is local all right, but then it's copied back to the caller (actually, moved).为了回答你的第二个问题,在 create() 中创建的对象是本地的,但是它被复制回调用者(实际上是移动的)。 Since the stack frame is the same, the local address is the same.由于堆栈帧相同,因此本地地址相同。 But when it's copied, you have two different objects.但是当它被复制时,你有两个不同的对象。

  1. create() returns a value, so during assignment which take place in A o1=A::create(1); create() 返回一个值,因此在A o1=A::create(1);发生的赋值期间A o1=A::create(1); , copy constructor should be called but it isn't. , 复制构造函数应该被调用,但它不是。 why?为什么?

You have copy-elision ( Demo ) which is an optimization allowed by standard.您有复制省略Demo ),这是标准允许的优化。

The object is directly constructed in final place and no copy/move is done.对象在最终位置直接构造,不进行复制/移动。

Some copy-elisions is even mandatory in C++17.某些复制省略在 C++17 中甚至是强制性的。 (half of them in your case). (在你的情况下有一半)。

  1. Is this some undefined behavior as the address of the object created in create() and in main() are same and the object in create() is local and goes out of scope after the function ends.这是一些未定义的行为,因为在 create() 和 main() 中创建的对象的地址相同,并且 create() 中的对象是本地的并且在函数结束后超出范围。

With copy elision, as object is directly constructed in final place, there is indeed only one address, it is as-if the local variable of create was the one from main .使用复制省略,因为对象是直接在最终位置构造的,所以确实只有一个地址,就好像create的局部变量是来自main变量。

Thanks for all the answers.感谢所有的答案。 Dug deep into it and now answering my own question.深入研究它,现在回答我自己的问题。

For the learned:对于所学:

This is major instance of copy elision in C++ 17.这是 C++ 17 中复制省略的主要实例。

Answer ends for you.答案为你结束。 For the one who still didn't understood:对于还没有理解的人:

This method has no errors and do not show any undefined behavior.此方法没有错误,也不会显示任何未定义的行为。 Most of the compilers uses C++11 or C++17 these days which is well integrated with copy elision(copy omission) .现在大多数编译器都使用 C++11 或 C++17,它们与copy elision(copy omission)很好地集成在一起。

create() returns a value, so during assignment which take place in A o1=A::create(1);, copy constructor should be called but it isn't. create() 返回一个值,因此在 A o1=A::create(1); 中发生的赋值期间,应该调用复制构造函数,但它不是。 why?为什么?

Copy constructor is not called as the return type is prvalue(pure rvalue) and the compiler optimizes the program in such a way that the return value is created directly into the storage where the function's return value would otherwise be copied or moved to.不会调用复制构造函数,因为返回类型是纯右值(纯右值) ,并且编译器以这样一种方式优化程序,即返回值直接创建到存储中,否则函数的返回值将被复制或移动到该存储中。 So, actually no move or copy takes place so no move/copy constructor is called.所以,实际上没有移动或复制发生,所以没有调用移动/复制构造函数。 Even after the end of create() destructor too is not called.即使在create()结束后也不会调用析构函数。

Is this some undefined behavior as the address of the object created in create() and in main() are same and the object in create() is local and goes out of scope after the function ends.这是一些未定义的行为,因为在 create() 和 main() 中创建的对象的地址相同,并且 create() 中的对象是本地的并且在函数结束后超出范围。

So, even after the function create() ends, the object dont get pushed out of scope or the destructor for that object is not called.因此,即使在函数create()结束后,对象也不会被推出范围或该对象的析构函数不会被调用。 As the object is created in not in the create() but in the main() itself.因为对象不是在create()create()而是在main()本身中创建的。 It is not an undefined behavior but a major benefit of C++ as unnecessary pointers and functions need not to be declared or invoked.这不是未定义的行为,而是 C++ 的一个主要好处,因为不需要声明或调用不必要的指针和函数。 Here, NRVO takes place.在这里,发生了NRVO

  • In a return statement, when the operand is the name of a non-volatile object with automatic storage duration, which isn't a function parameter or a catch clause parameter, and which is of the same class type (ignoring cv-qualification) as the function return type.在 return 语句中,当操作数是具有自动存储期的非易失性对象的名称时,该对象不是函数参数或 catch 子句参数,并且属于相同的类类型(忽略 cv 限定)作为函数返回类型。 This variant of copy elision is known as NRVO, "named return value optimization".这种复制省略的变体被称为 NRVO,“命名返回值优化”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM