为什么编译器需要一个复制构造函数,需要和移动一个,并且不使用任何它们? [英] Why does the compiler require a copying constructor, need and have moving one and doesn't uses any of them?

查看:187
本文介绍了为什么编译器需要一个复制构造函数,需要和移动一个,并且不使用任何它们?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经试过提出这个问题,但我不够清楚。所以这里是一个多尝试。对我的英语很抱歉)


让我们看看代码:

  #include< iostream> 
#include< memory>
using namespace std;

struct A {
unique_ptr< int> ref;

void printRef(){
if(ref.get())
cout<<i =<< * ref<< endl;
else
cout<<i = NULL<< endl;
}

A(const int i):ref(new int(i)){
cout<<Constructor with;
printRef();
}
〜A(){
cout<<Destructor with;
printRef();
}
};

int main()
{
A a [2] = {0,1};
return 0;
}

无法编译,因为 unique_ptr 复制构造函数。

Orly ?!

这个类有一个隐含的移动构造函数,因为unique_ptr有一个。


让我们做一个测试:

  #include< iostream> 
#include< memory>
using namespace std;

struct A {
unique_ptr< int>参考

void printRef(){
if(ref.get())
cout<<i =<< * ref<< endl;
else
cout<<i = NULL<< endl;
}

A(const int i):ref(new int(i)){
cout<<Constructor with;
printRef();
}
//让我们添加一个移动构造函数。
A(A& a):ref(std :: move(a.ref)){
cout<
printRef();
}
〜A(){
cout<<Destructor with;
printRef();
}
};

int main()
{
A a [2] = {0,1};
return 0;
}



我添加了一个移动构造函数,现在代码可以编译和执行。$
即使不使用移动构造函数。

输出:


构造函数with i = 0
¥b $ b构造函数with i = 1

析构函数withi = 1

析构函数withi = 0


好吧...让我们再做一次测试,并删除复制构造函数(但保留移动的构造函数)。

我不发布代码,只有一行已经添加:

  A(const A& )= delete; 

你应该相信我 - 因此,编译器不需要复制构造函数。
但它没有! (facepalm应该在这里)_
那么发生了什么事?我看到它完全不合逻辑!或者有没有某种扭曲的逻辑,我看不到?


一次:

unique_ptr 有一个移动的构造函数, 。编译器需要复制构造函数才能存在。但实际上编译器需要一个移动构造函数(即使它不被使用),并且不需要复制(因为它可以被删除)。而且我看到移动构造函数是(应该是)存在隐含。

这是什么问题?

还有一件事 - 如果我删除移动构造函数,程序无法编译。因此,移动构造函数是必需的,但不是复制一个。
为什么它需要复制构造函数,如果它被禁止在那里使用它?


P.P.S.
大感谢juanchopanza的回答!这可以通过以下方式解决:

  A(A& a)= default; 

也非常感谢Matt McNabb。

,移动构造函数不存在,因为 unique_ptr 没有复制一个类有一个析构函数(和一般规则是默认/复制/移动构造函数和析构函数默认情况下只生成所有在一起)。然后编译器不停止移动(为什么?!),并回到复制一个。在这一点上,编译器不能生成它,并且在没有其他可执行操作时停止错误(关于复制构造函数)。


顺便说一句,你添加:

  A(A& a)= delete; 
A(const A& a)= default;

无法编译有关'A :: A(A&



PPPS最后一个问题 - 为什么它会在COPY构造函数中停止错误,而不是MOVE构造函数?!

GCC ++ 4.7 / 4.8说:错误:使用删除的函数'A :: A(const A&)' br />
所以它停在复制构造函数。

为什么?应该有'A :: A(A&& amp;)'


好。现在看起来像一个关于移动/复制constrcutor选择规则的问题。

我创建了一个新的更具体的问题此处

解决方案

我想你问为什么

  A a [2] {0,1}; 

无法编译,而您期望编译它,因为 A 可能有一个移动构造函数。



原因是 A 有一个不可复制的成员,所以它自己的复制构造函数是 deleted ,并且这被视为一个用户声明的复制构造函数 有一个用户声明的析构函数



这反过来表示 A 没有隐式声明的move constructor 。您必须启用移动构建,您可以通过默认构造函数来执行:

  A(A&& 

要检查类是否是可移动构造的,可以使用 is_move_constructible ,从 type_traits 头:

  std: :cout< std :: boolalpha; 
std :: cout<< std :: is_move_constructible< A> :: value< std :: endl;

在您的情况下输出 false / p>

I've already tried to ask this question but I wasn't clear enough. So here is one more try. And I am very sorry for my English ;)

Let's see the code:

#include <iostream>
#include <memory>
using namespace std;

struct A {
    unique_ptr<int> ref;

    void printRef() {
        if (ref.get())
            cout<<"i="<<*ref<<endl;
        else
            cout<<"i=NULL"<<endl;
    }

    A(const int i) : ref(new int(i)) { 
        cout<<"Constructor with ";
        printRef();
    }
    ~A() {
        cout<<"Destructor with";
        printRef();
    }
};

int main()
{
    A a[2] = { 0, 1 };
   return 0;
}

It can not be compiled because unique_ptr has deleted copying constructor.
Orly?!
This class DOES HAVE an implied moving constructor because unique_ptr has one.

Let's do a test:

#include <iostream>
#include <memory>
using namespace std;

struct A {
    unique_ptr<int> ref;

    void printRef() {
        if (ref.get())
            cout<<"i="<<*ref<<endl;
        else
            cout<<"i=NULL"<<endl;
    }

    A(const int i) : ref(new int(i)) { 
        cout<<"Constructor with ";
        printRef();
    }
    // Let's add a moving constructor.
    A(A&& a) : ref(std::move(a.ref)) { 
        cout<<"Moving constructor with";
        printRef();
    }
    ~A() {
        cout<<"Destructor with";
        printRef();
    }
};

int main()
{
    A a[2] = { 0, 1 };
   return 0;
}

I've added a moving constructor and now the code can be compiled and executed.
Even if the moving constructor is not used.
The output:

Constructor with i=0
Constructor with i=1
Destructor withi=1
Destructor withi=0

Okay...
Let's do one more test and remove the copying constructor (but leave the moving one).
I don't post the code, there only one line has been added:

A(const A& a) = delete;

You should trust me - it works. So the compiler doesn't require a copying constructor. But it did! (a facepalm should be here)
So what's going on? I see it completely illogical! Or is there some sort of twisted logic I don't see?

Once more:
unique_ptr has a moving constructor and has a deleted copying constructor. Compiler requires copying constructor to be present. But in fact the compiler requires a moving constructor (even if it is not used) and doesn't require a copying (because it could be deleted). And as I see the moving constructor is (should be?) present impliedly.
What's wrong with that?

P.S. One more thing - if I delete the moving constructor the program could not be compiled. So the moving constructor is required, but not the copying one.
Why does it require copy-constructor if it's prohibited to use it there?

P.P.S. Big thanks to juanchopanza's answer! This can be solved by:

A(A&& a) = default;

And also big thanks to Matt McNabb.
As I see it now, the moving constructor is absent because unique_ptr doesn't have a copying one the class has a destructor (and the general rule is that default/copying/moving constructors and destructor could be generated by default only all together). Then the compiler doesn't stop at moving one (why?!) and falls back to copying one. At this point the compiler can't generate it and stops with an error (about the copy constructor) when nothing else can be done.

By the way it you add:

A(A&& a) = delete;
A(const A& a) = default;

It could NOT be compiled with error about 'A::A(A&& a)' deletion, There will be no fall back to copying constructor.

P.P.P.S The last question - why does it stop with error at the COPY constructor but not the MOVE constructor?!
GCC++ 4.7/4.8 says: "error: use of deleted function ‘A::A(const A&)’"
So it stops at copy constructor.
Why?! There should be 'A::A(A&&)'

Ok. Now it seems like a question about move/copy constrcutor choosing rule.
I've created the new more specific question here

解决方案

I think you are asking why this

A a[2] = { 0, 1 };

fails to compile, while you would expect it to compile because A may have a move constructor. But it doesn't.

The reason is that A has a member that is not copyable, so its own copy constructor is deleted, and this counts as a user declared copy constructor has a user-declared destructor.

This in turn means A has no implicitly declared move constructor. You have to enable move construction, which you can do by defaulting the constructor:

A(A&&) = default;

To check whether a class is move constructible, you can use is_move_constructible, from the type_traits header:

std::cout << std::boolalpha;
std::cout << std::is_move_constructible<A>::value << std::endl;

This outputs false in your case.

这篇关于为什么编译器需要一个复制构造函数,需要和移动一个,并且不使用任何它们?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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