`size_t`にはどのヘッダーを含める必要がありますか?


95

cppreference.comに よるとsize_t、いくつかのヘッダーで定義されています。

<cstddef>
<cstdio>
<cstring>
<ctime>

そして、C ++ 11以降、

<cstdlib>
<cwchar> 

まず第一に、これはなぜそうなのかと思います。これは、DRYの原則に反していませんか?しかし、私の質問は:

上記のヘッダーのどれを使用するために含める必要がありますsize_tか?それはまったく重要ですか?


1
対応するヘッダーファイルを開き、定義を見つけます。
i486

33
@ i486-これは、移植性のない脆弱なコードを記述するための優れた方法です。
Sean、

3
@PanagiotisKanavos C ++標準ライブラリの一部であり、おそらく「真のC ++」ヘッダーと重複していないCヘッダー。どういう意味でしたか?
underscore_d

14
私はいつも使ってい<cstddef>ましたstd::size_t
Boiethios

4
@PanagiotisKanavos確かに、一般的にそれは良いアドバイスですが、この場合は適切ではないようです-のC ++の代替はなくstd::size_t、OPはレガシーC関数の使用を推奨していなかったため、typedefを共有するそれらに関する引用を観察しただけです。このため、このスレッドを読んでいる人がレガシーの型/関数を誤用することはないと思いますが、そうでないことを確認したい場合は、十分に公正です!
underscore_d

回答:


90

インポートしていた関数と型を最小限にしたいと思ったので、 cstddefは宣言せず、6つの型のみを宣言するので、これを使用します。他の人はあなたにとって重要ではないかもしれない特定のドメイン(文字列、時間、IO)に焦点を合わせています。

グローバルネームスペース(事実上、プレーン)でもこの名前提供される場合がありますが、cstddef定義std::size_t、つまりsize_tネームスペースstdでの定義のみが保証されることに注意してください。size_t

対照的にstddef.h(これはCでも使用可能なヘッダーです)size_t、グローバル名前空間での定義が保証され、も提供される場合がありますstd::size_t


3
size_tfrom cstddefが同じであり、常に他のものと同じであるという保証はありますか?size_t...のような一般的な定義を持つ一般的なヘッダーファイルがあるはずです
SnakeDoc

1
@SnakeDocと、まるで魔法のように、ここでの別の答えは、「内部」ヘッダーを介して、まさにそれが起こっていることをすでに観察しています。
underscore_d

5
@SnakeDocはい、そのヘッダーはcstddefです。
user253751

2
@SnakeDoc、彼らは自分で自分を定義すると言っていますか?すべての標準では、これらのヘッダーを含めた後に定義されるということであり、すべてを再定義する必要があるとは言われていません。それらはすべて含めることも、<cstddef>定義するだけの内部ヘッダーを含めることもできますsize_t
ジョナサンウェイクリー

1
あるcsttddef答えではタイプミス?多分 cstddef意味ですか?
ErikSjölund2017

46

実際、いくつかのヘッダーの概要(C ++標準に含まれています)にはsize_t、追加のヘッダーだけでなく、特定のタイプも定義されていますsize_t<cX>ヘッダーは、ISO C <X.h>ヘッダーにすぎないため、Cの標準に基づいており、削除size_tは示されていません。

C ++標準では、しかし、を意味<cstddef>の定義についてstd::size_t

  • 18.2型
  • 中にはsizeof 5.3.3
  • 3.7.4.2割り当て解除関数(18.2指す)と
  • 3.7.4.1割り当て関数(また18.2を指します)。

したがって、<cstddef>タイプのみを導入し、関数は導入しないという事実のため、このヘッダーをstd::size_t使用できるようにします。


いくつか注意してください:

  1. のタイプは、ヘッダーを含めずにstd::size_t使用して取得できますdecltype

    あなたはしている計画は、とにかくあなたのコード内のtypedefを導入する場合(つまり、あなたは、コンテナを作成し、提供したいためsize_typeのtypedefを)あなたはグローバルに使用できるsizeofsizeof...またはalignoftheoseオペレータが戻るので、まったくのヘッダを含めずにあなたのタイプを定義するための演算子をstd::size_tあたりに標準的な定義とあなたはdecltypeそれらに使用することができます:

    using size_type = decltype(alignof(char));
  2. std::size_tstd::size_t引数付きの関数は表示されますが、それ自体はグローバルに表示されません。

    暗黙的に宣言されたグローバル割り当ておよび割り当て解除関数

    void* operator new(std::size_t);
    void* operator new[](std::size_t);
    void operator delete(void*);
    void operator delete[](void*);

    導入しないsize_tstdまたはstd::size_t

    適切なヘッダーを含めることによって名前が宣言されていない限り、参照stdまたはstd::size_t不正な形式です。

  3. std::size_t同じ名前空間内の同じ型を参照する複数のtypedefを持つことは可能ですが、ユーザーは再定義できません。

    size_t内での複数の定義の発生は7.1.3 / 3stdに従って完全に有効ですが、17.6.4.2.1 / 1に従って宣言を追加することは許可されていません。namespace std

    特に明記されていない限り、宣言または定義を名前空間stdまたは名前空間std内の名前空間に追加する場合、C ++プログラムの動作は未定義です。

    の適切なtypedefをsize_t名前空間に追加しても7.1.3には違反しませんが、17.6.4.2.1に違反し、未定義の動作を引き起こします。

    明確化:7.1.3を誤って解釈しないようにし、宣言や定義を追加しないでくださいstd(typedefがテンプレートの特殊化ではないいくつかのテンプレート特殊化の場合を除きます)。の拡張namespace std


1
重複したtypedefが新しい型を導入しないという事実を見逃します。完全に有効な重複したtypedefを追加するだけです。
Maxim Egorushkin 2016

@MaximEgorushkin:typedefのstd重複は違法であるため、typedefの再定義の追加が無効であるとは主張しません。私はそれが合法であるnamespace stdかどうかに関係なく、あなたが単に定義を追加しないかもしれないので、それは違法であると述べます。
Pixelchemist 2016

これらすべての標準的な見積もりからわかっていることを考えると、何が壊れる可能性がありますか?
Maxim Egorushkin 2016

12
@MaximEgorushkin:何でも。それが未定義の振る舞いです。そうではありませんか?それがポイント働くか、ということでもポイント任意のコンパイラには壊れないが、標準に従って定義されたプログラムの動作を行いません。または、 'fredoverflow'をここに適切に記述します。
Pixelchemist 2016

批判的思考を使っていただきたい。何が壊れる可能性がありますか?
Maxim Egorushkin 2016

9

すべての標準ライブラリヘッダーファイルの定義は同じです。自分のコードにどのコードを含めるかは関係ありません。私のコンピューターでは、に次の宣言があり_stddef.hます。このファイルは、リストしたすべてのファイルに含まれています。

/*
   Define the size_t type in the std namespace if in C++ or globally if in C.
   If we're in C++, make the _SIZE_T macro expand to std::size_t
*/

#if !defined(_SIZE_T) && !defined(_SIZE_T_DEFINED)
#  define _SIZE_T_DEFINED
#if defined(_WIN64)
   typedef unsigned __int64 size_t;
#else
   typedef unsigned int size_t;
#endif
#  if defined(__cplusplus)
#    define _SIZE_T std::size_t
#  else
#    define _SIZE_T size_t
#  endif
#endif

2
確かではありませんが、コンパイル時間には関係ないと思いますか?
idclev 463035818

@ tobi303はこの特定の質問ではありません。はい、必要以上に大きなヘッダーを追加することはできますが、C ++プロジェクトにすでに Cヘッダーを追加してます。size_tそもそもなぜ必要なのですか?
Panagiotis Kanavos

OSマクロのスニッフィングを使用してを定義することはお勧めできませんsize_t。より移植性の高いとして定義できますusing size_t = decltype( sizeof( 42 ) )。しかし、<stddef.h>ほとんどコストがかからないので、必要はありません。
乾杯とhth。-Alf

4

ヘッダーなしで行うことができます:

using size_t = decltype(sizeof(int));
using size_t = decltype(sizeof 1); //  The shortest is my favourite.
using size_t = decltype(sizeof "anything");

これは、C ++標準では次の要件があるためです。

sizeofand の結果は、sizeof...型の定数ですstd::size_t。[注:std::size_tは標準ヘッダー<cstddef>(18.2)で定義されています。—エンドノート]

言い換えると、この規格では以下が必要です。

static_assert(std::is_same<decltype(sizeof(int)), std::size_t>::value,
              "This never fails.");

また、同じtypedef-nameの他のすべての宣言と一致する限り、このtypedef宣言をグローバルとstdネームスペースで作成しても問題ないことに注意してください。typedefても問題ありません(一致しない宣言ではコンパイラエラーが発行されます)。

それの訳は:

  • §7.1.3.1typedef -nameは、クラス宣言(9.1)または列挙型宣言のように新しい型を導入しません。

  • §7.1.3.3特定の非クラススコープでは、typedef指定子を使用して、そのスコープで宣言されている型の名前を再定義し、すでに参照している型を参照できます。


これは名前空間への新しいタイプの追加を構成するものであると懐疑論者に stdであり、そのような行為は規格によって明示的に禁止されていること、そしてこれはUBであり、それだけのことです。この態度は、根本的な問題に対する深い理解を無視し、否定することに相当します。

標準では、新しい宣言と定義を名前空間に追加することを禁止stdしています。そうすることで、ユーザーは標準ライブラリを混乱させ、脚全体を撃ち落とす可能性があります。標準的なライターにとっては、ユーザーが行うべきではないすべてのことを禁止し、重要な何か(およびその脚)を見逃す危険を冒すよりも、ユーザーにいくつかの特定のことを専門にして、他のことを適切に禁止する方が簡単でした。彼らは過去に、標準コンテナを不完全な型でインスタンス化しないことを要求するときにそれを行いましたが、実際には一部のコンテナはうまくいくことができます(Matthew H. Austernによる標準ライブラリアン:不​​完全型のコンテナを参照):

...結局のところ、それはすべてあまりに曖昧で、あまりによく理解されていないように見えました。標準化委員会は、STLコンテナーが不完全な型で動作することは想定されていないことを除いて、選択肢はないと考えていました。適切な対策として、その禁止を他の標準ライブラリにも適用しました。

...振り返ってみると、テクノロジーがよりよく理解された今、その決定は依然として基本的に正しいようです。はい、一部の標準コンテナを実装して、不完全な型でインスタンス化できる場合もありますが、それ以外の場合は困難または不可能であることも明らかです。ほとんどの場合、私たちが最初に試したテストは、偶然にもstd::vector簡単なケースの1つでした。

言語規則std::size_tが厳密にdecltype(sizeof(int))である必要があることを考えると、実行namespace std { using size_t = decltype(sizeof(int)); }は何も壊さないものの1つです。

C ++ 11より前のdecltypeバージョンではsizeof、1つの単純なステートメントで結果のタイプを宣言する方法がなかったため、大量のテンプレートを使用する必要がありました。size_tは、さまざまなターゲットアーキテクチャでさまざまな型のエイリアスを作成しますが、の結果のためだけに新しい組み込み型を追加するのは洗練されたソリューションsizeofではなく、標準の組み込み型定義はありません。したがって、当時最も移植性の高い解決策は、size_tタイプエイリアスを特定のヘッダーに挿入し、それを文書化することでした。

C ++ 11には、規格の正確な要件を1つの単純な宣言として書き留める方法があります。


6
@Seanあなたが書いたものは意味がありません。
Maxim Egorushkin 2016

15
@MaximEgorushkinそれらの半分はこのコードを理解していません...それは完全に動作します。ただし、私はこの方法が好きではありません。imoを使用して、ヘッダーを含め、標準で定義することをお勧めします。
Boiethios

9
みんな、完全に正しい答えに投票する前に、少なくとも効果的な言語を学んでください。
フレデリックハ

11
トムは「同じことを定義している6つの標準ライブラリヘッダーがあります。それは非常識です!の定義は1つだけ必要size_tです!」1分後、メアリーは言った、「OMG!size_t標準ライブラリヘッダー全体で7つの定義があり、トムが編集しているプロジェクトヘッダーがある!サードパーティのライブラリにはおそらくもっとある!」xkcd.com/927

6
size_tこれはの可能な定義ですが、これはOPの実際の質問には答えません。つまり、FILE宣言されているヘッダーを要求したかのようになり、独自のヘッダーを作成することをお勧めします。
edmz
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.