C++ 调用 LLVM 中隐式删除的复制构造函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19559503/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 22:57:43  来源:igfitidea点击:

Call to implicitly deleted copy constructor in LLVM

c++c++11default-copy-constructor

提问by cpp_hex

As per C++11 rules 6 things (default constructor, copy constructor, move constructor, copy assignment, move assignment and destructor ) are generated by default. By second rule, when any custom copy, move or destructor is defined then those default operations are not generated. But in my code that follows that is not the case. But this code fails to compile with an error

根据 C++11 规则,默认生成 6 个事物(默认构造函数、复制构造函数、移动构造函数、复制赋值、移动赋值和析构函数)。根据第二条规则,当定义任何自定义复制、移动或析构函数时,不会生成这些默认操作。但在我接下来的代码中,情况并非如此。但是此代码无法编译并出现错误

call to implicitly deleted copy constructor of 'Uni'

When I write my own copy constructor for Uni everything works fine. (It is commented in the code, given for reference )

当我为 Uni 编写自己的复制构造函数时,一切正常。(代码中有注释,仅供参考)

Any thoughts much appreciated.

任何想法都非常感谢。

Finally , I am running this on Mac, Xcode with LLVM compiler.

最后,我在 Mac、Xcode 和 LLVM 编译器上运行它。

many thanks...

非常感谢...

#include <iostream>

class A
{
public:
    A(int i) :num{i}
    {
        std::clog<< "ctor  A() num = " << num << "\n";

    }
    A( A const &aRef)
    :num{aRef.num}
    {
        std::clog << " copy ctor A( A const &aRef) num = " << num << "\n";
    }

    int value()
    {
        return num;
    }

private:
    int num;

};
class Uni
{

public:
    Uni(A* aptr) : up{aptr}
    {
        std::clog << " ctor Uni value = " << up.get()->value() << "\n";
    }
    /*Uni(Uni const &uRef)
    {
        std::clog << " copy ctor Uni copying obj pointed by unique_ptr\n";
        up.reset(uRef.up.get() ? new A{*uRef.up.get()} : nullptr);
    }*/
private:
    std::unique_ptr<A> up;

};

int main(int argc, const char * argv[])
{
    Uni one{new A{10}};
    Uni two{one}; //default copy ctor is implicitly deleted. why ?
}

回答by Angew is no longer proud of SO

C++11 rules for automatic generation of special members aren't as simple as you posted them. The most important distinction is that in some cases, the member is implicitly declared, but defined as deleted. That's what happens in your case.

自动生成特殊成员的 C++11 规则并不像您发布的那么简单。最重要的区别是,在某些情况下,成员是隐式声明的,但定义为已删除。这就是你的情况。

C++11, [class.copy]§11:

C++11,[class.copy]§11:

A defaulted copy/move constructor for a class Xis defined as deleted (8.4.3) if Xhas:

  • a variant member with a non-trivial corresponding constructor and Xis a union-like class,
  • a non-static data member of class type M(or array thereof) that cannot be copied/moved because overload resolution (13.3), as applied to M's corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor,
  • a direct or virtual base class Bthat cannot be copied/moved because overload resolution (13.3), as applied to B's corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor,
  • any direct or virtual base class or non-static data member of a type with a destructor that is deleted or inaccessible from the defaulted constructor,
  • for the copy constructor, a non-static data member of rvalue reference type, or
  • for the move constructor, a non-static data member or direct or virtual base class with a type that does not have a move constructor and is not trivially copyable.

X如果X具有以下条件,则类的默认复制/移动构造函数被定义为已删除(8.4.3):

  • 具有非平凡对应构造函数的变体成员,并且X是类似联合的类,
  • M无法复制/移动的类类型(或其数组)的非静态数据成员,因为应用于M的相应构造函数的重载决议 (13.3) 会导致歧义或从默认值中删除或无法访问的函数构造函数,
  • B无法复制/移动的直接或虚拟基类,因为应用于B的相应构造函数的重载决议 (13.3) 会导致歧义或从默认构造函数中删除或无法访问的函数,
  • 具有从默认构造函数中删除或无法访问的析构函数的类型的任何直接或虚拟基类或非静态数据成员,
  • 对于复制构造函数,右值引用类型的非静态数据成员,或
  • 对于移动构造函数,非静态数据成员或直接或虚拟基类,其类型没有移动构造函数且不可简单复制。

(Emphasis mine)

(强调我的)



More generally, the rules for auto-generated class members are:

更一般地,自动生成的类成员的规则是:

  • If the class has no user-provided constructors, a default constructor is declared.

  • If the class doesn't have a user-provided copy constructor, one is declared.

  • If the class has none of { user-provided copy or move constructor, user-provided copy or move assignment operator, user-provided destructor }, a move constructor will be declared (but see (*) below).

  • If the class doesn't have a user-provided copy assignment operator, one is declared.

  • If the class has none of { user-provided copy or move constructor, user-provided copy or move assignment operator, user-provided destructor }, a move assignment operator will be declared (but see (*) below).

  • If the class doesn't have a user-provided destructor, one is declared.

  • 如果类没有用户提供的构造函数,则声明默认构造函数。

  • 如果该类没有用户提供的复制构造函数,则声明一个。

  • 如果该类没有 { 用户提供的复制或移动构造函数、用户提供的复制或移动赋值运算符、用户提供的析构函数 },则将声明移动构造函数(但请参阅下面的 (*))。

  • 如果该类没有用户提供的复制赋值运算符,则声明一个。

  • 如果该类没有 { 用户提供的复制或移动构造函数、用户提供的复制或移动赋值运算符、用户提供的析构函数 },则将声明移动赋值运算符(但请参阅下面的 (*))。

  • 如果类没有用户提供的析构函数,则声明一个。

Any automatically declared member can be defined as defaulted (doing the default stuff) or defined as deleted (if you try to use it, you get an error). The rule of thumb is "If the defaulted version makes sense, it will be defined as defaulted. Otherwise, it will be defined as deleted."

任何自动声明的成员都可以定义为默认的(做默认的事情)或定义为删除的(如果你尝试使用它,你会得到一个错误)。经验法则是“如果默认版本有意义,则将其定义为默认版本。否则,将其定义为删除。”

In this context, "makes sense" means "doesn't try to call a deleted, ambiguous, inaccessible or otherwise illegal function." For example, the standard bit I quoted in the first part of this answer lists what doesn't "make sense" for copy constructors.

在这种情况下,“有意义”的意思是“不会尝试调用已删除、模棱两可、无法访问或以其他方式非法的函数”。例如,我在本答案第一部分引用的标准位列出了对于复制构造函数“没有意义”的内容。

Additionally, an automatically declared copy constructor or copy assignment operator is defined as deleted if the class has a user-provided move constructor or move assignment operator.

此外,如果类具有用户提供的移动构造函数或移动赋值运算符,则自动声明的复制构造函数或复制赋值运算符被定义为已删除。

(*) If an automatically declared move constructor or move assignment operator would be defined as deleted, it is instead not declared at all. This rule exists so that trying to move such a class implicitly falls back to copying it instead of generating an error.

(*) 如果自动声明的移动构造函数或移动赋值运算符将被定义为已删除,则根本不声明它。这条规则的存在使得试图移动这样一个类隐式地回退到复制它而不是产生错误。