当与移动构件配对时,发生意外的析构函数调用 [英] Unexpected destructor call occurs when paired with move constuctor

查看:195
本文介绍了当与移动构件配对时,发生意外的析构函数调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码在Visual Studio 2012 Express for Windows Desktop中编译并运行,作为一个学习练习。

  #include < cstdio> 

class X
{
public:
X(){printf(default constructed \\\
); }
〜X(){printf(destructed\\\
);}
X(const X&){printf }
X(X&&;){printf(move constructed \\\
); }
X& operator =(const X&){printf(copy assignment operator\\\
); }
};

X A(){
X x;
return x;
}

int main(){
{
A();
}
std :: getchar();
}



当编译时禁用编译器优化(/ Od)时,析构函数被调用两次。这是一个问题,假设只构造一个对象。 为什么析构函数被调用两次?如果类管理自己的资源,这不会是一个问题?

 默认构造
移动构造
破坏
破坏<<意外调用

我尝试了几个实验来尝试和解释输出,

实验1:当使用优化(/ O1或/ O2)编译相同的代码时,结果输出为:

 默认构造
破坏


b $ b

这表示命名返回值优化已经省略了对move构造函数的调用,并掩盖了底层问题。



实验2:禁用优化并注释掉移动构造函数。

 默认构造
构造的拷贝
destructed
destructed


解决方案

虽然Michael和jspcal的答案是准确的,回答我的问题的核心,这是为什么有两个析构函数调用。我期待只有一个。



答案是函数A()返回一个临时对象。总是。这是函数返回值如何工作,移动语义与这个事实没有关系。我猜Michael和jspcal假设我没有错过这样的基本事实。我把移动一词与交换的概念等同起来。当交换时,对象不被构造和破坏。因此,我期望只有一个析构函数调用。



由于返回的对象必须被构造和析构,所以第二个析构函数调用(和第二个构造函数调用) p>

现在,选择要执行的实际构造函数取决于类定义中提供的内容。如果移动构造函数可用,将被调用。否则将调用复制构造函数。


The following code was compiled and run in Visual Studio 2012 Express for Windows Desktop, as a learning exercise.

#include <cstdio>

class X
{
public:
    X()  { printf("default constructed\n"); }
    ~X() { printf("destructed\n");}
    X(const X&) { printf("copy constructed\n"); }
    X(X&&) { printf("move constructed\n"); }
    X & operator= (const X &) { printf("copy assignment operator\n"); }
};

X A() {
    X x;
    return x;
}

int main() {
    {
        A();
    }
    std::getchar();
}

When compiled with compiler optimizations disabled (/Od), the resulting output indicates that the destructor is called twice. This is a problem given that only one object is constructed. Why is the destructor being called twice? Wouldn't this be a problem if the class was managing it own resources?

default constructed
move constructed
destructed
destructed   <<< Unexpected call 

I tried a couple of experiments to try and explain the output, but ultimately these didn't lead to any useful explanations.

Experiment 1: When the same code is compiled with optimizations enabled (/O1 or /O2), the resulting output is:

default constructed
destructed

which indicates that the Named Return Value Optimization has elided the call to the move constructor, and masked the underlying problem.

Experiment 2: Disabled the optimization and commented out the move constructor. The output generated was what I expected.

default constructed
copy constructed
destructed
destructed

解决方案

Although Michael's and jspcal answers are accurate, they didn't answer the heart of my question, which was why were there two destructor calls made. I was expecting just one.

The answer is that function A() returns a temporary object. Always. This is how function return values work, and move-semantics has no bearing on this fact. I guess Michael and jspcal assumed that I had not missed such a basic fact. I equated the term "moved" with the concept of "swap". When swapped, objects are not constructed and destructed. Hence I was expecting just one destructor call.

Since the returned object must be constructed and destructed, the second destructor call was made (and a second constructor call).

Now, the actual constructor selected to be executed depends on what is provided in the class definition. If a move-constructor is available, that will be called. Otherwise the copy constructor will be called.

这篇关于当与移动构件配对时,发生意外的析构函数调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆