其他分享
首页 > 其他分享> > c – 为什么编译器需要复制构造函数,需要并且移动一个并且不使用它们中的任何一个?

c – 为什么编译器需要复制构造函数,需要并且移动一个并且不使用它们中的任何一个?

作者:互联网

我已经尝试过问这个问题,但我还不够清楚.所以这是另一个尝试.我对我的英语很抱歉;)
我们来看看代码:

#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已删除复制构造函数.
奥利?
这个类有一个隐含的移动构造函数,因为unique_ptr有一个.
我们来做一个测试:

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

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

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

好的……让我们再做一次测试并删除复制构造函数(但保留移动构造函数).
我没有发布代码,只添加了一行:

A(const A& 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&& a)’删除,复制构造函数不会回退.

P.P.P.S最后一个问题 – 为什么它会在COPY构造函数中停止,而不是MOVE构造函数?!
GCC 4.7 / 4.8说:“错误:使用删除的函数’A :: A(const A&)’”
所以它在复制构造函数处停止.
为什么?!应该有’A :: A(A&&)’
好.现在,这似乎是一个关于移动/复制建设者选择规则的问题.
我已经创建了新的更具体的问题here

解决方法:

我想你在问为什么这个

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

无法编译,而你期望它编译,因为A可能有一个移动构造函数.但事实并非如此.

原因是A有一个不可复制的成员,因此它自己的复制构造函数被删除,这被视为用户声明的复制构造函数具有用户声明的析构函数.

这反过来means A has no implicitly declared move constructor.你必须启用移动构造,你可以通过默认构造函数来做:

A(A&&) = default;

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

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

在您的情况下输出为false.

标签:move-constructor,c,c11,constructor,copy-constructor
来源: https://codeday.me/bug/20191007/1866380.html