web-dev-qa-db-ja.com

「size_t」に含めるヘッダーはどれですか?

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

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

また、C++ 11以降では、

<cstdlib>
<cwchar> 

まず第一に、なぜそうなのか疑問に思います。これは DRY の原則と矛盾していませんか?しかし、私の質問は次のとおりです。

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

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

cstddefstd::size_tの定義のみを保証することに注意してください。つまり、名前空間stdsize_tを定義しますが、mayグローバル名前空間(事実上、プレーンsize_t)。

対照的に、stddef.h(Cでも使用可能なヘッダー)は、グローバル名前空間でsize_tを定義することを保証し、maystd::size_tを提供します。

70
Sean

すべての標準ライブラリヘッダーファイルの定義は同じです。どちらを自分のコードに含めるかは関係ありません。私のコンピューターでは、_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
9
Ville-Valtteri

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

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

これは、C++標準が以下を必要とするためです。

sizeofsizeof...の結果は、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)またはenum宣言のように新しい型を導入しません。

  • §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の結果のためだけに新しい組み込み型を追加するのはエレガントなソリューションではなく、標準の組み込みtypedefはありません。したがって、当時の最も移植性の高いソリューションは、特定のヘッダーにsize_tタイプエイリアスを挿入し、それを文書化することでした。

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

4