Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么在返回临时值(右值)时在移动构造函数之前调用析构函数_C++_Move Semantics_Temporary - Fatal编程技术网

C++ 为什么在返回临时值(右值)时在移动构造函数之前调用析构函数

C++ 为什么在返回临时值(右值)时在移动构造函数之前调用析构函数,c++,move-semantics,temporary,C++,Move Semantics,Temporary,我怀疑我对移动语义学有些不理解。给定以下代码,我希望调试器(MSVC2010SP1)按以下顺序调用代理的成员: Proxy(Resource*)在getProxy Proxy(Proxy&other)movep ~Proxy()销毁临时文件的空壳,临时文件被移动夺走了内脏 ~Proxy()p超出范围 class Resource { void open(){} public: void close(){} Proxy && getProxy(); };

我怀疑我对移动语义学有些不理解。给定以下代码,我希望调试器(MSVC2010SP1)按以下顺序调用代理的成员:

  • Proxy(Resource*)
    getProxy
  • Proxy(Proxy&other)
    move
    p
  • ~Proxy()
    销毁临时文件的空壳,临时文件被移动夺走了内脏
  • ~Proxy()p
    超出范围

    class Resource
    {
        void open(){}
    public:
        void close(){}
        Proxy && getProxy();
    };
    class Proxy
    {
        Resource *pResource_;
        Proxy(const Proxy& other); //disabled
        Proxy& operator=(const Proxy& other); //disabled
    public:
        Proxy(Resource *pResource):pResource_(pResource){}
        Proxy(Proxy&& other):pResource_(other.pResource_){other.pResource_ = nullptr;}
        ~Proxy()
        {
            if(pResource_)
                pResource_->close();
            pResource_ = nullptr;
        }
    };
    
    Proxy && Resource::getProxy()
    {
            open();
            return Proxy(this);
    }
    
    //somewhere else, lets say in main()
    Resource r;
    {
        auto p = r.getProxy(); 
    }   // p goes out of scope
    
相反,顺序是:

  • Proxy(Proxy*)
  • ~Proxy()
    //这已经比预期更早地调用了
    close()
  • Proxy(Proxy&&other)
    //销毁后移动会使
    p.pResource
    的值为
    nullptr
  • ~Proxy()
    /
    p
    超出范围

这对我来说毫无意义。我要做的是跟踪代理类的生存期,该代理类通过move构造函数将关闭资源的任务从一个对象传递到另一个对象。

getProxy()
返回对临时,这超出了函数末尾的范围,并导致一个悬空引用。

通过右值引用返回实际上不会导致任何内容被移动。它只是通过引用返回。但是,它与返回左值引用不同,因为调用返回右值引用的函数的表达式是xvalue(与左值相反)。然后可以从中移动xvalue(作为右值表达式的子集)。如果要从返回左值引用的函数的返回对象移动,则必须使用
std::move
使其成为右值

您很少希望实际返回右值引用。它唯一模糊的常用用法是允许从中移动对象的私有成员。如果希望在从函数返回对象时移动对象,只需按值返回即可。在您的情况下,如果
getProxy
的返回类型只是
Proxy
,则临时对象将从移动到返回的对象中,然后该对象将从移动到
p
(保存以备省略)


正如您所拥有的,您的临时对象(由
代理(this)
构造)在
return
语句末尾被销毁-这是析构函数的第一次调用。返回的引用现在引用的是无效对象,
p
是通过从此无效引用移动而构造的。这会给您带来未定义的行为。

我们不知道您如何创建/返回其中一个对象,但我怀疑您返回了对本地对象的引用,这是一个nono@PlasmaHH抱歉,没有发布所有代码(需要咖啡),您几乎不应该使用右值引用作为返回类型。只需使用类类型允许通过移动构造函数返回。是否保证返回值将被移动构造?@PorkyBrain:如果返回临时或函数本地类变量或
std::move(something)
,且返回类型为类类型,然后要么返回值将被move构造,要么复制/移动将被完全省略。啊,我想我理解了,所以通过声明返回类型Proxy&&我基本上是返回一个Proxy&具有特权,它可以通过move?@PorkyBrain获得它的勇气。您仍在返回一个引用,因此它必须有支持。在您的情况下,您应该只按值返回。如果您想将某个对象移出对象,则返回右值引用是有意义的(
return std::move(this->something);
)。