C++初心者に贈る強そうな人からC++のclassに関連する謎な用語を使われたときにみるもの: trivialとか

# 強そうな人からC++のclassに関連する謎な用語を使われたときにみるもの

C++を使うにあたって規格書を読まないということはありえないので、どうしても専門用語が多くなっしまいます。

誰かに質問したときに謎な専門用語が混じっていることもあるかと思います。そんな時のためにかるく解説をします。

ただし、
[C++入門者に贈るclass入門とclass/structキーワードの使い分け](http://qiita.com/yumetodo/items/b0ff58617f2733d4ffa1)
の内容を理解していることを前提とします。

以下、規格書の引用部分でバージョン間で差異のある部分、及びそれに該当する解説箇所は<font color="red">赤字</font>で示します。

# 追記

お知らせするのを完全に忘れていたのですが、

https://cpprefjp.github.io/reference/type_traits/is_trivially_copyable.html

に[C++20に対応させた内容を記載した](https://github.com/cpprefjp/site/pull/768)のでそちらを参照してください。

# user-declared

残念ながら規格書を読んでも判然としません。ただ、ユーザーが関数を宣言したら`user-declared`になるようです。`= default`/`= delete` 指定も含むと解するべきかと思われます。
言い換えると、`= delete` 指定しても宣言は残っている、と。

宣言が残っていればいいんですね。

- [特殊メンバ関数とコンパイラによる暗黙宣言 - yohhoyの日記](http://d.hatena.ne.jp/yohhoy/20140704/p1)

# user-provided

>N3337(C++11)
>§ 8.4.2.5 dcl.fct.def.default
>A <font color="red">special member function</font> is `user-provided` if it is user-declared and **not explicitly defaulted or deleted** on its first declaration.

>N4140(C++14)
>§ 8.4.2.5 dcl.fct.def.default
>A <font color="red">function</font> is `user-provided` if it is user-declared and **not explicitly defaulted or deleted** on its first declaration.

>N4659(C++17)
>§ 11.4.2.5 dcl.fct.def.default
>A <font color="red">function</font> is `user-provided` if it is user-declared and **not explicitly defaulted or deleted** on its first declaration.

not A or Bは、`(!A && !B) <=> !(A || B)`という意味なので、not explicitlyはdefaultedとdeletedにかかっています。
cf.) https://oshiete.goo.ne.jp/qa/2089050.html
andまで含めて解釈すると、`A && (!(B || C))`と解釈するべきです。

つまり、先の`user-declared`から`= default`/`= delete` 指定されたものを除くもの、となっています。C++11だと特殊メンバ関数に対してのみの定義になっていますが、言っていることとしては同じですね。

**大事なことだからもう一度、`= default`/`= delete` 指定されたものはuser-providedではありません。**

```cpp:C++
class Hoge {
public:
  Hoge() {}//user-provided
  Hoge(const Hoge&) = default;//not user-provided, but user-declared
  Hoge(Hoge&&) = delete;//not user-provided, but user-declared
};
int f(Hoge&&);//user-provided
int f(const Hoge&) = delete;//not user-provided, but user-declared

int main(){
  Hoge h;
  //f(h);
  f(Hoge());
}
```

こういうことか？宣言の形態についてであって、定義についてはみていなさそう。

# trivial

それ単体は規格では定義されていません。英単語的には、自明な、というような意味らしいです。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">&quot;trivial&quot;というのは&quot;コンパイラがシンボルを作成する必要がない&quot;ということのような気がするな。もちろん規格には実装がどう振る舞うかは書いてないわけだけど</p>&mdash; 白山風露 (@kazatsuyu) <a href="https://twitter.com/kazatsuyu/status/873176362550411264">2017年6月9日</a></blockquote>
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">まあtrivialだからってシンボルを作成しないとも限りませんしね<a href="https://t.co/h6XFHBdTsh">https://t.co/h6XFHBdTsh</a></p>&mdash; 白山風露 (@kazatsuyu) <a href="https://twitter.com/kazatsuyu/status/873399548483297280">2017年6月10日</a></blockquote>

ただこのあと見ていくように`user-provided`ではないことが最低要件になっていて、そうするとこの推測は正しい気がします。ゆるふわ定義。

# trivialなデストラクタを持つ(has a trivial destructor)

>N3337(C++11)
>§ 12.4.5 class.dtor
>A destructor is trivial if it is not user-provided and if:
>— the destructor is not virtual,
>— all of the direct base classes of its class have trivial destructors, and
>— for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial destructor.
>Otherwise, the destructor is *non-trivial*.

>N4140(C++14)
>§ 12.4.5 class.dtor
>5 A destructor is trivial if it is not user-provided and if:
>(5.4) — the destructor is not virtual,
>(5.5) — all of the direct base classes of its class have trivial destructors, and
>(5.6) — for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial destructor.
>Otherwise, the destructor is *non-trivial*.


>N4659(C++17)
>§ 15.4.6 class.dtor
>6 A destructor is trivial if it is not user-provided and if:
>(6.1) — the destructor is not virtual,
>(6.2) — all of the direct base classes of its class have trivial destructors, and
>(6.3) — for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial destructor.
> Otherwise, the destructor is *non-trivial*.

C++17で定義している節が移動しましたが、内容は変わっていません。

対象となるクラスがtrivialなデストラクタを持つためには

- デストラクタは`user-provided`ではない
- デストラクターはvirtualではない

ことが大前提になります。

`user-provided`ではない、とは**`= default`/`= delete` 指定していてもいい**、ということです。
デストラクタをdeleteってどういうこと？という人は
[C++ - C++11で、デストラクタ = deleteとする意味について(35601)｜teratail](https://teratail.com/questions/35601)
を見に行きましょう。

さらに

- 非staticデータメンバーのデストラクターは、すべてtrivialである

非staticメンバ変数にも上記の2条件が適応されます。

もし対象となるクラスが基底クラスを保つ場合は(なんか継承している場合)

- 直接の基底クラスのデストラクターは、すべてtrivialである

このように追加条件があります。これは言い換えると、継承関係にあるクラスのうち基底クラス方向すべてのクラスが上記3条件を満たす必要があるということです。
なぜならvirtual指定された関数と同名の関数を派生クラスで定義するとそれもvirtualになるからです。もちろんデストラクタも例外ではありません。
cf.) [そのoverride指定は合法ですか？違法ですか？](http://qiita.com/yumetodo/items/f3ceb1a64a1540f85568)

C++で継承関係を作るとき、多くの場合安全性を考えて基底クラスのデストラクタをvirtual指定します。
[C++では基底クラスにvirtualデストラクタを書こう - ＊「ふっかつのじゅもんがちがいます。」withぬこ](http://d.hatena.ne.jp/ajiyoshi/20080925/p1)
しかし、その時点でtrivialなデストラクタを持っていないんですね。

デストラクターはvirtualではない、とは

```cpp:C++
class HasNotUserProvidedVitrualDtorClass {
public:
  virtual ~HasNotUserProvidedVitrualDtorClass() = default;
};
```

`= default`指定されたvirtualデストラクタを除外するための条件です。

# trivialに破棄可能(trivially destructible)

trivialに破棄可能とは、

- trivialなデストラクタを持つ(has a trivial destructor)
- **デストラクタが削除されていない**(is destructible)

の2条件を満たすものを言います。**trivialなデストラクタを持つ、とtrivialに破棄可能、は同義ではありません**

デストラクタが削除されていない、とは`=delete`指定されている場合(explicitly deleted)や、暗黙に削除されている場合などを含みます。
これは[`std::is_destructible`](https://cpprefjp.github.io/reference/type_traits/is_destructible.html)で調査可能です。

条件をみたすかどうかは、[`std::is_trivially_destructible`](https://cpprefjp.github.io/reference/type_traits/is_trivially_destructible.html)で調べることができます。

```cpp:C++
#include <type_traits>

struct C1 {
  // トリビアルなデストラクタを持っている

  // 特殊関数ではないメンバ関数は持っている
  int f(int x) const { return x; }
};

struct C2 {
  // 非トリビアルなデストラクタを持っている
  ~C2() {}
};
// 組み込み型は全てトリビアルに破棄可能
static_assert(std::is_trivially_destructible<int>::value == true, "int is trivially destructible");
static_assert(std::is_trivially_destructible<int*>::value == true, "int* is trivially destructible");

// ユーザー定義型は、ユーザー定義のデストラクタを持っていなければトリビアルに破棄可能
static_assert(std::is_trivially_destructible<C1>::value == true, "C1 is trivially destructible");
static_assert(std::is_trivially_destructible<C2>::value == false, "C2 isn't trivially destructible");

int main() {}
```

* `CC BY 3.0`: https://cpprefjp.github.io/reference/type_traits/is_trivially_destructible.html

# trivialなコピー/ムーブコンストラクタを持つ(has a trivial copy/move constructor)

>N3337(C++11)
>§ 12.8 class.copy
>12 A copy/move constructor for class X is trivial if it is not user-provided and if
>— class X **has no virtual functions** (10.3) and no virtual base classes (10.1), and
>— the constructor selected to copy/move each direct base class subobject is trivial, and
>— for each non-static data member of X that is of class type (or array thereof), the constructor selected to copy/move that member is trivial;
>otherwise the copy/move constructor is *non-trivial*.

>N4140(C++14)
>§ 12.8 class.copy
>12 A copy/move constructor for class X is trivial if it is not user-provided<font color="red">, its parameter-type-list is equivalent to the parameter-type-list of an implicit declaration, </font>and if
(12.1) — class X **has no virtual functions** (10.3) and no virtual base classes (10.1), and
<font color="red">(12.2) — class X **has no non-static data members of volatile-qualified type**, and</font>
(12.3) — the constructor selected to copy/move each direct base class subobject is trivial, and
(12.4) — for each non-static data member of X that is of class type (or array thereof), the constructor selected to copy/move that member is trivial;
otherwise the copy/move constructor is *non-trivial*.

>N4569(C++17)
>§ 15.8.1 class.copy.ctor
>11 A copy/move constructor for class X is trivial if it is not user-provided and if:
>(11.1) — class X **has no virtual functions** (13.3) and no virtual base classes (13.1), and
>(11.2) — the constructor selected to copy/move each direct base class subobject is trivial, and
>(11.3) — for each non-static data member of X that is of class type (or array thereof), the constructor selected to copy/move that member is trivial;
otherwise the copy/move constructor is *non-trivial*.

ただし、[CWG issue 2171](https://wg21.cmeerw.net/cwg/issue2171)により、以下の文面は削除されます。

> , its parameter-type-list is equivalent to the parameter-type-list of an implicit declaration, 

また、[CWG issue 2094](https://wg21.cmeerw.net/cwg/issue2094)により、以下の文面は削除されます。

> class X has no non-static data members of volatile-qualified type, and

C++17から定義している節が移動しました。

対象となるクラスがtrivialなコピー/ムーブコンストラクタを持つためには

- コピー/ムーブコンストラクタは`user-provided`ではない
- **virtual関数を持たず**、virtual基本クラスも持たない
- <font color="red">(C++14のみ、[CWG issue 2171](https://wg21.cmeerw.net/cwg/issue2171)適用前のみ)</font>コンストラクタ/代入演算子の仮引数リストが暗黙に宣言された場合の仮引数リストと同じ
- <font color="red">(C++14のみ、[CWG issue 2094](https://wg21.cmeerw.net/cwg/issue2094)適用前のみ)</font>volatile修飾された型の非staticデータメンバーを持たない

が前提条件です。また、

- クラス型か、クラスの配列型の非staticデータメンバーをコピー/ムーブするのに使われるコンストラクターがトリビアルであること

非staticメンバ変数についても先の4条件が適応されます。

もし対象となるクラスが基底クラスを保つ場合は(なんか継承している場合)

- 直接の基底クラスのサブオブジェクトをコピー/ムーブするのに使われるコンストラクターがトリビアルであること

このように追加条件があります。これは言い換えると、継承関係にあるクラスのうち基底クラス方向すべてのクラスが上記5条件を満たす必要があるということです。

trivialなデストラクタの要件と大きく違うのは、**virtual関数を持っていはいけない**ことでしょうか。

~~仮引数リストが暗黙に宣言された場合の仮引数リストと同じ、というのは**正直何言っているのかわからない**です。ユーザー定義してはいけないんだから嫌でも暗黙に宣言された場合の仮引数リストと同じになると思うんですが・・・。
これはあれか？コピー/ムーブコンストラクタを`= delete`する場合は`X(const X&)`/`X(X&&)`に対してのみ`= delete`しろってことか？しかもこの文言、C++14のみあるんだよな・・・、何なんだ一体・・・。~~[CWG issue 2171](https://wg21.cmeerw.net/cwg/issue2171)により削除されました

volatileの話もなぜかC++14だけあって**よくわからない**です。

# tirivalにコピー/ムーブ構築可能(trivially copy/move constructible)

tirivalにコピー/ムーブ構築可能、であるためには

- trivialなコピー/ムーブコンストラクタを持つ(has copy/move constructor)
- コピー/ムーブ構築可能(is copy/move constructible)

の2条件を満たす必要があります。

コピー/ムーブ構築可能とは、特定の引数のときに構築可能(is constructible)、に定義がたらい回されており、これは

>N3337(C++11)
>§ 20.10.4.3 meta.unary.prop
>6 <font color="red">Given the following function prototype:</font>
>
```cpp
template <class T>
typename add_rvalue_reference<T>::type create();
```

>the predicate condition for a template specialization `is_constructible<T, Args...>` shall be satisfied if and only if the following variable definition would be well-formed for some invented variable t:
>
```cpp
T t(create<Args>()...);
```

>*[ Note:* These tokens are never interpreted as a function declaration. *—end note ]* Access checking is
performed as if in a context unrelated to `T` and any of the `Args`. Only the validity of the immediate context of the variable initialization is considered. *[ Note:* The evaluation of the initialization can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the “immediate context” and can result in the program being ill-formed. *—end note ]*

>N4140(C++14)
>§ 20.10.4.3 meta.unary.prop
>7 <font color="red">Given the following function prototype:</font>
>
```cpp
template <class T>
add_rvalue_reference_t<T> create() noexcept;
```

>the predicate condition for a template specialization `is_constructible<T, Args...>` shall be satisfied if and only if the following variable definition would be well-formed for some invented variable t:
>
```cpp
T t(create<Args>()...);
```

>*[ Note:* These tokens are never interpreted as a function declaration. *—end note ]* Access checking is performed as if in a context unrelated to `T` and any of the `Args`. Only the validity of the immediate context of the variable initialization is considered. *[ Note:* The evaluation of the initialization can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the “immediate context” and can result in the program being ill-formed. *—end note ]*

>N4569
>§ 23.15.4.3 meta.unary.prop
>8 The predicate condition for a template specialization `is_constructible<T, Args...>` shall be satisfied if and only if the following variable definition would be well-formed for some invented variable t:
>
```cpp
T t(declval<Args>()...);
```

>*[ Note:* These tokens are never interpreted as a function declaration. *—end note ]* Access checking is performed as if in a context unrelated to `T` and any of the `Args`. Only the validity of the immediate context of the variable initialization is considered. *[ Note:* The evaluation of the initialization can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the “immediate context” and can result in the program being ill-formed. *—end note ]*

まあなんかごちゃごちゃ書いている上にC++17から[`std::declval`](https://cpprefjp.github.io/reference/utility/declval.html)を使う定義に書き換わっていますが、ようはpublicに宣言されているコンストラクタに指定の引数を渡して見たときにエラーが起きない、つまり呼び出せれば特定の引数のときに構築可能(is constructible)だ、という極めてありきたりな定義になっています。これは[`std::is_constrictible`](https://cpprefjp.github.io/reference/type_traits/is_constructible.html)で調べられます。

で、話を戻してtirivalにコピー/ムーブ構築可能かどうかは[`std::is_trivially_copy_constructible`](https://cpprefjp.github.io/reference/type_traits/is_trivially_copy_constructible.html)/[`std::is_trivially_move_constructible`](https://cpprefjp.github.io/reference/type_traits/is_trivially_move_constructible.html)で調べられます。

# trivialなコピー/ムーブ代入演算子を持つ(trivially copy/move assignable)

>N3337(C++11)
>§ 12.8 class.copy
>25 A copy/move assignment operator for class X is trivial if it is not user-provided and if
>— class X **has no virtual functions** (10.3) and no virtual base classes (10.1), and
— the assignment operator selected to copy/move each direct base class subobject is trivial, and
— for each non-static data member of X that is of class type (or array thereof), the assignment operator selected to copy/move that member is trivial;
>otherwise the copy/move assignment operator is *non-trivial*.
>
>N4140(C++14)
>§ 12.8 class.copy
>25 A copy/move assignment operator for class X is trivial if it is not user-provided<font color="red">, its parameter-type-list is equivalent to the parameter-type-list of an implicit declaration, </font>and if
(25.1) — class X **has no virtual functions** (10.3) and no virtual base classes (10.1), and
<font color="red">(25.2) — class X **has no non-static data members of volatile-qualified type**, and</font>
(25.3) — the assignment operator selected to copy/move each direct base class subobject is trivial, and
>(25.4) — for each non-static data member of X that is of class type (or array thereof), the assignment operator selected to copy/move that member is trivial;
otherwise the copy/move assignment operator is *non-trivial*.
>
>N4659(C++17)
>§ 15.8.2 class.copy.assign
>9 A copy/move assignment operator for class X is trivial if it is not user-provided and if:
(9.1) — class X **has no virtual functions** (13.3) and no virtual base classes (13.1), and
(9.2) — the assignment operator selected to copy/move each direct base class subobject is trivial, and
(9.3) — for each non-static data member of X that is of class type (or array thereof), the assignment operator selected to copy/move that member is trivial;
otherwise the copy/move assignment operator is *non-trivial*.

ただし、[CWG issue 2171](https://wg21.cmeerw.net/cwg/issue2171)により、以下の文面は削除されます。

> , its parameter-type-list is equivalent to the parameter-type-list of an implicit declaration, 

また、[CWG issue 2094](https://wg21.cmeerw.net/cwg/issue2094)により、以下の文面は削除されます。

> class X has no non-static data members of volatile-qualified type, and

**基本的に「trivialなコピー/ムーブコンストラクタを持つ」と同じです**

対象となるクラスがtrivialなコピー/ムーブ代入演算子を持つためには

- コピー/ムーブ代入演算子は`user-provided`ではない
- **virtual関数を持たず**、virtual基本クラスも持たない
- <font color="red">(C++14のみ、[CWG issue 2171](https://wg21.cmeerw.net/cwg/issue2171)適用前のみ)</font>コンストラクタ/代入演算子の仮引数リストが暗黙に宣言された場合の仮引数リストと同じ
- <font color="red">(C++14のみ、[CWG issue 2094](https://wg21.cmeerw.net/cwg/issue2094)適用前のみ)</font>volatile修飾された型の非staticデータメンバーを持たない

が前提条件です。また、

- クラスXのクラス型とクラスの配列型の非staticデータメンバーの、コピー/ムーブに使われる代入演算子がトリビアル

非staticメンバ変数についても先の4条件が適応されます。

もし対象となるクラスが基底クラスを保つ場合は(なんか継承している場合)

- 直接の基底クラスのサブオブジェクトで使われるコピー/ムーブの代入演算子がトリビアル

このように追加条件があります。これは言い換えると、継承関係にあるクラスのうち基底クラス方向すべてのクラスが上記5条件を満たす必要があるということです。

で、例によって脳内で調べるのは限界があるので[`std::is_trivially_copy_assignable`](https://cpprefjp.github.io/reference/type_traits/is_trivially_copy_assignable.html)/[`std::is_trivially_move_assignable`](https://cpprefjp.github.io/reference/type_traits/is_trivially_move_assignable.html)があります。

# トリビアルにコピー可能なクラス(trivially copyable class)

この定義が[CWG issue 1734](https://wg21.cmeerw.net/cwg/issue1734)適用前後で大きく変わっているのでそれぞれ考察していきましょう。

## [CWG issue 1734](https://wg21.cmeerw.net/cwg/issue1734)適用前

C++11とC++14の差分については上述の通り[CWG issue 2171](https://wg21.cmeerw.net/cwg/issue2171)と[CWG issue 2094](https://wg21.cmeerw.net/cwg/issue2094)によって打ち消されるので、C++11の文面を見ていきます。

>N3337(C++11)
>§ 9. class
>6 A trivially copyable class is a class that:
— has no non-trivial copy constructors (12.8),
— has no non-trivial move constructors (12.8),
— has no non-trivial copy assignment operators (13.5.3, 12.8),
— has no non-trivial move assignment operators (13.5.3, 12.8), and
— has a trivial destructor (12.4).
A trivial class is a class that has a trivial default constructor (12.1) and is trivially copyable.
[ Note: In particular, a trivially copyable or trivial class does not have virtual functions or virtual base classes.—end note ]

[CWG issue 1734](https://wg21.cmeerw.net/cwg/issue1734)適用前では、対象となるクラスがtrivially copyable classであるためには、

- trivialではないコピーコンストラクタを持たない
- trivialではないムーブコンストラクタを持たない
- trivialではないコピー代入演算子を持たない
- trivialではないムーブ代入演算子を持たない
- trivialなデストラクタを持つ

を満たす必要があります。

「trivialではない～を持たない」ってすごく回りくどいですね。「すべての～はtrivial」と解釈しましょう。

それを踏まえ、上のまとめを合体して解釈すると

- デストラクターはvirtualではない
- デストラクタと全てのコピー/ムーブ コンストラクタ/代入演算子は`user-provided`ではない
- **virtual関数を持たず**、virtual基本クラスも持たない

さらに

- 非staticデータメンバーのデストラクターは、すべてtrivialである
- クラス型か、クラスの配列型の非staticデータメンバーをコピー/ムーブするのに使われるコンストラクターがトリビアルであること
- クラスXのクラス型とクラスの配列型の非staticデータメンバーの、コピー/ムーブに使われる代入演算子がトリビアル

非staticメンバ変数にも上記の3条件が適応されます。

もし対象となるクラスが基底クラスを保つ場合は(なんか継承している場合)

- 直接の基底クラスのデストラクターは、すべてtrivialである
- 直接の基底クラスのサブオブジェクトをコピー/ムーブするのに使われるコンストラクターがトリビアルであること
- 直接の基底クラスのサブオブジェクトで使われるコピー/ムーブの代入演算子がトリビアル

このように追加条件があります。これは言い換えると、継承関係にあるクラスのうち基底クラス方向すべてのクラスが上記6条件を満たす必要があるということです。

**問題点はデストラクタが`= delete`指定されていてもいいということです。**

## C++17 or [CWG issue 1734](https://wg21.cmeerw.net/cwg/issue1734)適用後

>N4659(C++17)
>§ 12. class
>6 A trivially copyable class is a class:
(6.1) — where each copy constructor, move constructor, copy assignment operator, and move assignment operator (15.8, 16.5.3) is either deleted or trivial,
(6.2) — that has at least one non-deleted copy constructor, move constructor, copy assignment operator, or move assignment operator, and
(6.3) — that has a trivial, non-deleted destructor (15.4).
A trivial class is a class that is trivially copyable and has one or more default constructors (15.1), all of which are either trivial or deleted and at least one of which is not deleted. [ Note: In particular, a trivially copyable or trivial class does not have virtual functions or virtual base classes.—end note ]

C++17 or [CWG issue 1734](https://wg21.cmeerw.net/cwg/issue1734)適用後では、対象となるクラスがtrivially copyable classであるためには、

- 全てのコピー/ムーブ コンストラクタ/代入演算子はtrivialもしくは`= delete`指定されている
- コピー/ムーブ コンストラクタ/代入演算子のうち少なくとも1つは`= delete`指定されていない
- trivialで`= delete`指定されていないデストラクタを持つ

を満たす必要があります。

[CWG issue 1734](https://wg21.cmeerw.net/cwg/issue1734)適用前と比べると、回りくどい書き方をやめてスッキリしましたね。また実質的な定義にも変更があります。

1つ目の「trivialもしくは`= delete`指定されている」というのは**冗長**です。ここまで見てきたようにtrivialに`= delete`指定は含まれますからね。多分2つ目と3つ目で「`= delete`指定されていない」と書いたので対称性の観点からわざわざ書いてくれたんでしょう。

上のまとめを合体して解釈すると

- デストラクターはvirtualではない
- **デストラクターは`= delete`指定されていない**
- デストラクタと全てのコピー/ムーブ コンストラクタ/代入演算子は`user-provided`ではない
- **virtual関数を持たず**、virtual基本クラスも持たない
- **コピー/ムーブ コンストラクタ/代入演算子のうち少なくとも1つは`= delete`指定されていない**

さらに

- 非staticデータメンバーのデストラクターは、すべてtrivialである
- クラス型か、クラスの配列型の非staticデータメンバーをコピー/ムーブするのに使われるコンストラクターがトリビアルであること
- クラスXのクラス型とクラスの配列型の非staticデータメンバーの、コピー/ムーブに使われる代入演算子がトリビアル

非staticメンバ変数にも上記の5条件が適応されます。

もし対象となるクラスが基底クラスを保つ場合は(なんか継承している場合)

- 直接の基底クラスのデストラクターは、すべてtrivialである
- 直接の基底クラスのサブオブジェクトをコピー/ムーブするのに使われるコンストラクターがトリビアルであること
- 直接の基底クラスのサブオブジェクトで使われるコピー/ムーブの代入演算子がトリビアル

このように追加条件があります。これは言い換えると、**継承関係にあるクラスのうち基底クラス方向すべてのクラスが**上記8条件を満たす必要があるということです。

## trivially copyable classの嬉しいこと

**trivially copyable classであれば、`memcpy`関数などで単純なバイト列のコピーができるようになります**。

>[本の虫: C++0xにおけるPODの定義](https://cpplover.blogspot.jp/2010/06/c0xpod.html)
>つまり、memcpyでコピー出来るクラスの制限は、だいぶ緩和される。まず、コンストラクタがあってもいいし、継承していてもいい。standard-layout classである必要はない。派生クラスと基本クラスが、共に非staticなデータメンバーをもっていても構わない。アクセス指定もできる。

# trivialなクラス(trivial class)

この概念はもともとPODを説明するために必要だったのですが、後述の通りPOD自体がC++20でdeprecatedになったのでこいつも忘れていいです。

そういうわけであまり重要な議論ではないので割愛したかったのですが、規格の文章だけ上でちらっと出てしまっているので引っ張り直しておきます。

>N3337(C++11)
>§ 9. class
>A trivial class is a class that has a trivial default constructor (12.1) and is trivially copyable.
[ Note: In particular, a trivially copyable or trivial class does not have virtual functions or virtual base classes.—end note ]
>
>N4140(C++14)
>§ 9. class
>A trivial class is a class that has a default constructor (12.1), has no non-trivial default constructors, and is trivially copyable. [ Note: In particular, a trivially copyable or trivial class does not have virtual functions or virtual base classes.—end note ]
>
>N4659(C++17)
>§ 12. class
>A trivial class is a class that is trivially copyable and has one or more default constructors (15.1), all of which are either trivial or deleted and at least one of which is not deleted. [ Note: In particular, a trivially copyable or trivial class does not have virtual functions or virtual base classes.—end note ]

ただし、[CWG issue 1496](https://wg21.cmeerw.net/cwg/issue1496)により、C++11/C++14の文面はC++17相当になります。

C++17でone or more default constructorsとか言い出したんですが、デフォルトコンストラクタが複数ってどういうコッチャ・・・

# standard-layoutなクラス(standard-layout class)

2017年にこの記事を書き始めたときは解説する気満々だったんですが、執筆を放置していたら

[C++における標準レイアウトクラスの定義](https://qiita.com/nus_miz/items/d09bfda40d5cc0866675)

先を越されました。こっち見てください。

こいつにはPODの説明以外にちゃんと役割があるので大切です。

>[本の虫: PODじゃなくてもいいのでは。](https://cpplover.blogspot.com/2010/05/pod.html)
> standard-layout class
>
>このクラスは、オブジェクトへのポインターは、クラスの最初のデータメンバーを指し示すことを保証するものである。**つまり、reinterpret_castを使って、オブジェクトへのポインターを、最初のデータメンバーのポインターにキャストした場合、ポインターは、最初のデータメンバーを指すことが保証される。**

# PODなクラス(pod class)

C++20からdeprecatedになる概念です。

>[本の虫: C++0xにおけるPODの定義](https://cpplover.blogspot.com/2010/06/c0xpod.html)
>PODは、trivial classかつstandard-layout classであること。
>さらに、非PODな非staticデータメンバーを持たないこと。

**PODのことは忘れましょう**。そういうのは考古学者に任せるべきです。

# 参考リンク

## Working Draft, Standard for Programming Language C++

- [PDF注意][N3337](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf): C++11 first post-publication draft
- [PDF注意][N4140](https://github.com/cplusplus/draft/blob/master/papers/n4140.pdf?raw=true): C++14 final draft
- [PDF注意][N4569](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf): C++17 final draft

## C++ Standard Core Language Issues

- [1496](https://wg21.cmeerw.net/cwg/issue1496). Triviality with deleted and missing default constructors
- [1590](https://wg21.cmeerw.net/cwg/issue1590). Bypassing non-copy/move constructor copying
- [1734](https://wg21.cmeerw.net/cwg/issue1734). Nontrivial deleted copy functions
- [1928](https://wg21.cmeerw.net/cwg/issue1928). Triviality of deleted special member functions
- [2094](https://wg21.cmeerw.net/cwg/issue2094). 
    Trivial copy/move constructor for class with volatile member
- [2171](https://wg21.cmeerw.net/cwg/issue2171). 
    Triviality of copy constructor with less-qualified parameter

## JTC1/SC22/WG21 - Papers

- [N4148](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4148.html): Disallowing Inaccessible Operators From Trivially Copyable

## C++11: Syntax and Feature(江添亮)

- [C++11: Syntax and Feature](http://ezoeryou.github.io/cpp-book/C++11-Syntax-and-Feature.xhtml)

## 本の虫 - 江添亮のブログ

- 2010-05-13: [PODじゃなくてもいいのでは。](https://cpplover.blogspot.jp/2010/05/pod.html)
- 2010-06-09: [C++0xにおけるPODの定義](https://cpplover.blogspot.jp/2010/06/c0xpod.html)

## cpprefjp C++日本語リファレンス

- [`std::is_trivially_copyable`(C++11)](https://cpprefjp.github.io/reference/type_traits/is_trivially_copyable.html)
- [`std::is_trivially_move_assignable`(C++11)](https://cpprefjp.github.io/reference/type_traits/is_trivially_move_assignable.html)

## Other Links about C++

- 2010-03-08: [デストラクタを呼ばずに再構築 - melpon日記 - HaskellもC++もまともに扱えないへたれのページ](http://d.hatena.ne.jp/melpon/20100308/1267998293)
- 2010-05-07: [C++でデストラクタを呼ばなくていい条件 - 野良C++erの雑記帳](http://d.hatena.ne.jp/gintenlabo/20100507/1273261890)
- 2010-05-13: [C++0xではPODでもコンストラクタ相当のことができる・・・？ - Faith and Brave - C++で遊ぼう](http://faithandbrave.hateblo.jp/entry/20100513/1273732111)
- 2012-11-22: [trivial class - C++と色々](http://nekko1119.hatenablog.com/entry/20121122/1353576526)
- 2014-07-04: [特殊メンバ関数とコンパイラによる暗黙宣言 - yohhoyの日記](http://d.hatena.ne.jp/yohhoy/20140704/p1)
- 2016-05-21: [C++ - C++11で、デストラクタ = deleteとする意味について(35601)｜teratail](https://teratail.com/questions/35601)
- 2017-06-09: [@EzoeRyou@friends.nico 突然すみません。C - yumetodo - Pawoo](https://pawoo.net/@yumetodo/19093347)

## Other Links

- [not～orとnot～nor - 英語 解決済 | 教えて!goo](https://oshiete.goo.ne.jp/qa/2089050.html)

# 追記

CWG issueのdefect reportの解釈を誤っていました。
[標準C++の欠陥解決は、過去のバージョンに遡って適用される - Faith and Brave - C++で遊ぼう](https://faithandbrave.hateblo.jp/entry/2017/08/10/120545)
によれば、defectとして採択されたCWG issueは採択された時点で処理系が適用します。つまり、defect reportとは対象となる問題が存在するすべてのISOで発行されたC++規格書のバージョンに対して適用されるものなのです。

これを踏まえて本文、とくにもっとも根幹のtrivially copyable classの定義に大幅な変更が生じました。

# License

[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/deed.ja)

<a href="https://commons.wikimedia.org/wiki/File:CC-BY_icon.svg#/media/File:CC-BY_icon.svg"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/CC-BY_icon.svg/1200px-CC-BY_icon.svg.png" alt="CC-BY icon.svg" width="88px"></a>

<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>