【问题标题】:C++11 compiler generated functionsC++11 编译器生成的函数
【发布时间】:2013-10-26 12:06:03
【问题描述】:

说一堂课

class Piece {} ;

如果我是正确的,那应该相当于:

class Piece {
   //C++ 03
    Piece ();                          //default constructor
    Piece( const Piece&);              //copy constructor
    Piece& operator=(const Piece&);    //copy assignment operator
    ~Piece();                          //destructor

    //Since C++ 11
    Piece(Piece&&);                   //move constructor
    Piece& operator=(Piece&&);        //move assignment operator
};

那么我能说些什么呢?

一)

class Pawn{
    ~Pawn() {}// Only destructor
};

b)

class Bishop{
    Bishop(Bishop&& ) {}// Only move constructor
};

c)

class Knight{
    Knight(Knight&&, int =0) {} // move constructor, when no second arg present
};

d)

class Rook {
    Rook(const Rook& ) {}// Only copy constructor
};

e)

class King{
        King& operator=(const King&) = delete;
    };

根据我的理解,编译器将生成:

  • a) 默认构造函数,复制构造函数,复制赋值运算符,(移动构造函数/赋值运算符?)
  • b) 析构函数
  • c) 析构函数
  • d) 复制赋值运算符和析构函数(移动构造函数/赋值运算符?)
  • e) 默认构造函数、复制构造函数、析构函数(移动构造函数/赋值运算符?)

我在这里是正确还是遗漏了什么?

基本上C++11有什么新的生成函数的规则,当用户没有提供的时候?

【问题讨论】:

  • 只有在原型后面加上= default,你的第一段代码才是正确的。如果您自己实现它们,它们将不再是微不足道的,并使类成为非 POD 等。
  • @KonradRudolph:“如果我是正确的,那应该等同于” 可能翻译为“这会为我生成以下默认构造函数/赋值运算符”,因为它应该反映class Piece{};中可用的运算符/构造函数
  • “等价”是一个糟糕的词选择。还是有区别的,这是关于琐碎,可以通过std::is_trivially_copyable 特征等检测到。而“编译器”与这个问题无关。语言规则决定了隐式声明和隐式定义的内容。
  • @KerrekSB 抱歉,请随时重新措辞/短语/编辑
  • 拼出所有不同的案例太痛苦了。我很确定我们已经在 SO 上有关于此的有用帖子,否则请获取标准的副本并自己阅读第 12.8 节。它非常清晰易读。

标签: c++ c++11


【解决方案1】:

我会在这里省略一些不相关的点,例如关于unions、基类、brace-or-equal-initializers 等。如果你的类有任何成员、基类……那么答案会有所不同。例如,如果您有一个 const 成员,则隐式声明的赋值运算符将被定义为已删除。

默认构造函数

[class.ctor]/5

X 类的默认构造函数是 X 类的构造函数,可以不带参数调用。如果类X 没有用户声明的构造函数,则没有参数的构造函数被隐式声明为默认值。隐式声明的默认构造函数是其类的 inline public 成员。 X 类的默认构造函数在 [...很多点与此无关] 时被定义为删除。

因此,在 a) 和 e) 的情况下 [没有任何用户声明的 ctor],默认 ctor 被声明为默认值。

默认析构函数

[class.dtor]

4 如果类没有用户声明的析构函数,则析构函数被隐式声明为默认值。隐式声明的析构函数是其类的 inline public 成员。

5 类X 的默认析构函数被定义为删除如果[...很多点在这里无关]

所以在所有情况下,除了 a) [使用用户声明的 dtor],默认 dtor 会被隐式声明并在使用 odr 时隐式定义。


根据 [class.copy]/2+3,copy-ctor 和 move-ctor 可能有额外的参数,如果它们有默认参数的话。

复制构造函数

如果没有用户定义的 copy-ctor(ctor 模板永远不是 copy-ctor),则隐式声明一个 copy-ctor。 [class.copy]/7

如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数被定义为删除;否则,它被定义为默认值。如果类具有用户声明的复制赋值运算符或用户声明的析构函数,则不推荐使用后一种情况。

也就是说,除了 d) [使用用户声明的 copy-ctor] 之外的所有情况下,都会隐式声明一个 copy-ctor。在情况 b) 和 c) [使用用户提供的移动 ctor] 中,复制 ctor 被定义为已删除。对于 a) [user-declared dtor] 和 e) [user-declared copy-assignment op],可以将其定义为默认值,但已弃用。

移动构造函数

在这些情况下甚至不会声明 move-ctor [class.copy]/9

  • X 没有用户声明的复制构造函数,
  • X 没有用户声明的复制赋值运算符,
  • X 没有用户声明的移动赋值运算符,
  • X 没有用户声明的析构函数,并且
  • 移动构造函数不会被隐式定义为已删除。

还有相当多的情况下它会被定义为删除,但它们并不适用于此。

因此,在任何情况下都声明了 move-ctor。


复制赋值运算符

在 [class.copy]/18 中:

如果类定义没有显式声明复制赋值运算符,则隐式声明一个。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制赋值运算符被定义为删除;否则,它被定义为默认值。如果类具有用户声明的复制构造函数或用户声明的析构函数,则不推荐使用后一种情况。

在某些情况下被定义为删除,参见[class.copy]/23,但这里不适用。

在所有情况下都声明了复制分配操作,但 e) [用户声明的复制分配操作]。在 b) 和 c) 中定义为删除 [both: user-declared move ctor];它可以在 a) [user-declared dtor] 和 d) [user-declared copy-ctor] 中定义为默认值。请注意与 copy-ctor 的相似之处。

移动赋值运算符

类似于 move-ctor,如果 [class.copy]/20:

  • X 没有用户声明的复制构造函数,
  • X 没有用户声明的移动构造函数,
  • X 没有用户声明的复制赋值运算符,
  • X 没有用户声明的析构函数,并且
  • 移动赋值运算符不会被隐式定义为已删除。

在某些情况下它被定义为删除,请参阅 [class.copy]/23(与 copy-ctor 相同的段落),但它们不适用于此处。

一个 move-assignment-op 被隐式声明并在 none 的情况下定义为默认值。

【讨论】:

  • 我认为删除了一个(例如复制构造函数),如果甚至声明了其他一个(例如析构函数)
  • @BЈовић 好吧,对于 move-ctor 和 move-assignment 操作来说是这样,但对于它们的副本来说却不是。也许是因为兼容性?已声明但已删除的函数参与重载决议。
  • 感谢您的参考
【解决方案2】:

所以看了一些帖子和在线教程,我得出了这样的结论:

生成的函数:-

  • C++ 03:

    1) 默认构造函数(仅在用户未声明构造函数时生成)

    2) Copy Constructor(仅在用户声明5,6号时生成)

    3) 复制赋值运算符(仅在用户未声明 5,6 时生成)

    4) 析构函数

  • 从 C++ 11 开始:

    5) 移动构造函数(仅在用户未声明 2,3,4,6 时生成)

    6) 移动赋值运算符(仅在用户未声明 2,3,4,5 时生成)


所以,对于

一)

class Pawn{ //1, 2, 3
    ~Pawn() {}// Only destructor
};

b)

class Bishop{ //4
    Bishop(Bishop&& ) {}
};

c)

class Knight{ //4
    Knight(Knight&&, int =0) {} 
};

d)

class Rook { //3, 4
    Rook(const Rook& ) {}
};

e)

class King{ //1, 2, 4
        King& operator=(const King&) = delete;
    };

编辑:根据 DyP 评论:-

在 C++11 中,

对于情况 a),不推荐使用 2 和 3。

对于情况 d),不推荐使用 3。

对于案例 e),不推荐使用 2。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-08
    • 1970-01-01
    相关资源
    最近更新 更多