C++11 编译器生成的函数
C++11 compiler generated functions
说一个类
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
是否有任何用于生成函数的新规则?
我将在这里省略一些不相关的要点,例如关于 union
、基类、大括号或等于初始值设定项等。如果您的类有任何成员、基类、...那么答案会有所不同。例如,如果您有一个const
成员,则隐式声明的赋值运算符将被定义为已删除。
默认构造函数
[类]/5
类
X
的默认构造函数是类X
的构造函数,无需参数即可调用。如果类X
没有用户声明的构造函数,则没有参数的构造函数被隐式声明为默认值。隐式声明的默认构造函数是其类的inline public
成员。类X
的默认构造函数定义为删除,如果 [...很多观点在这里无关紧要]。
因此,在 a) 和 e) [没有任何用户声明的 ctor] 的情况下,默认 ctor 被声明为默认值。
默认析构函数
[类.dtor]
4 如果类没有用户声明的析构函数,则析构函数将隐式声明为默认值。隐式声明的析构函数是其类的
inline public
成员。5 类
X
的默认析构函数定义为删除,如果 [...很多观点在这里无关紧要]
因此,在所有情况下,除了 a) [使用用户声明的 dtor],默认 dtor 被隐式声明,如果使用 odr,则隐式定义。
根据 [class.copy]/2+3,copy-ctor 和 move-ctor 可能有其他参数,如果它们有默认参数。
复制构造函数
如果没有用户定义的复制 ctor(ctor 模板从来都不是复制 ctor),则会隐式声明复制 ctor。[类.副本]/7
如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数定义为已删除;否则,它被定义为默认值。如果类具有用户声明的复制赋值运算符或用户声明的析构函数,则不推荐使用后一种情况。
也就是说,在除 d) [使用用户声明的 copy-ctor] 之外的所有情况下,都会隐式声明 copy-ctor。在 b) 和 c) [使用用户提供的移动 ctor] 的情况下,复制 ctor 定义为已删除。对于 a) [用户声明的 dtor] 和 e) [用户声明的复制分配操作],它可能被定义为默认值,但这已被弃用。
移动构造函数
在这些情况下,甚至不会声明移动 ctor [class.copy]/9
同样,在
X
没有用户声明的复制构造函数,X
没有用户声明的复制赋值运算符,X
没有用户声明的移动分配运算符,X
没有用户声明的析构函数,并且- 移动构造函数不会隐式定义为已删除。
相当多的情况下,它会被定义为删除,但它们在这里不适用。
因此,在任何情况下都不会声明移动。
复制赋值运算符
在 [class.copy]/18 中:
如果类定义未显式声明复制赋值运算符,则隐式声明一个。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制赋值运算符定义为已删除;否则,它被定义为默认值。如果类具有用户声明的复制构造函数或用户声明的析构函数,则不推荐使用后一种情况。
在某些情况下,它被定义为已删除,请参阅 [class.copy]/23,但它们在这里不适用。
在所有情况下都声明复制分配操作,但 e) [用户声明的复制分配操作]。它被定义为在b)和c)中删除[两者都:用户声明的移动ctor];它可以在 a) [用户声明的 dtor] 和 d) [用户声明的复制 CTOR] 中定义为默认值。请注意与复制者的并行。
移动赋值运算符
与 move-ctor 类似,如果 [class.copy]/20
:
X
没有用户声明的复制构造函数,X
没有用户声明的移动构造函数,X
没有用户声明的复制赋值运算符,X
没有用户声明的析构函数,并且- 移动分配运算符不会隐式定义为已删除。
在某些情况下,它被定义为删除,请参阅 [class.copy]/23(与 copy-ctor 的段落相同),但它们在这里不适用。
移动分配操作是隐式声明的,并且在任何情况下都定义为默认值。
所以看了一些帖子和在线教程,我得出了这样的结论:
生成的函数:-
-
C++03:
1) 默认构造函数(仅当用户未声明构造函数时才生成)
2) 复制构造函数(仅在用户声明第 5、6 号时才生成)
3) 复制赋值运算符(仅在用户未声明 5,6 时才生成)
4) 析构函数
-
自 11 C++以来:
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。
- 是否有C++编译器选项允许激进地删除所有函数调用,并将参数传递给具有空体的函数
- C++错误C2600:无法定义编译器生成的特殊成员函数(必须首先在类中声明)
- 我需要知道编译器如何在cpp中使用析构函数
- 编译器如何区分std::vector的构造函数
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 编译器如何在使用SFINAE的函数和标准函数之间确定两者是否可行
- 编译器警告:执行到达值返回函数的末尾而不返回值
- 填充上编译器生成的复制构造函数之间的不一致
- 编译器找不到'aligned_alloc'函数
- 这个C++编译器优化(在自身的实例上调用对象自己的构造函数)的名称是什么,它是如何工作的?
- 为什么编译器将其解析为函数指针而不是递归调用?
- 表达式未评估为常数两个级别的constexpr函数(编译器错误?)
- 从 std::streambif 继承时不兼容析构函数编译器警告
- 在构造函数 - 编译器错误中调用的成员变量的驱动器
- 复制初始化和显式构造函数-编译器的差异
- 静态函数编译器优化C++
- 为什么派生类虚函数可以调用基类虚函数?编译器如何实现
- 复制构造函数 - 编译器错误 C2040 和 C2440
- 带有模板返回类型的虚基函数:编译器在使用pointtype作为模板参数的派生类时失败(MSVC 2013)
- C++中虚拟函数编译器的作用