cppreference.comに よるとsize_t
、いくつかのヘッダーで定義されています。
<cstddef>
<cstdio>
<cstring>
<ctime>
そして、C ++ 11以降、
<cstdlib>
<cwchar>
まず第一に、これはなぜそうなのかと思います。これは、DRYの原則に反していませんか?しかし、私の質問は:
上記のヘッダーのどれを使用するために含める必要がありますsize_t
か?それはまったく重要ですか?
cppreference.comに よるとsize_t
、いくつかのヘッダーで定義されています。
<cstddef>
<cstdio>
<cstring>
<ctime>
そして、C ++ 11以降、
<cstdlib>
<cwchar>
まず第一に、これはなぜそうなのかと思います。これは、DRYの原則に反していませんか?しかし、私の質問は:
上記のヘッダーのどれを使用するために含める必要がありますsize_t
か?それはまったく重要ですか?
<cstddef>
ましたstd::size_t
std::size_t
、OPはレガシーC関数の使用を推奨していなかったため、typedefを共有するそれらに関する引用を観察しただけです。このため、このスレッドを読んでいる人がレガシーの型/関数を誤用することはないと思いますが、そうでないことを確認したい場合は、十分に公正です!
回答:
インポートしていた関数と型を最小限にしたいと思ったので、 cstddef
は宣言せず、6つの型のみを宣言するので、これを使用します。他の人はあなたにとって重要ではないかもしれない特定のドメイン(文字列、時間、IO)に焦点を合わせています。
グローバルネームスペース(事実上、プレーン)でもこの名前が提供される場合がありますが、cstddef
定義std::size_t
、つまりsize_t
ネームスペースstd
での定義のみが保証されることに注意してください。size_t
対照的にstddef.h
(これはCでも使用可能なヘッダーです)size_t
、グローバル名前空間での定義が保証され、も提供される場合がありますstd::size_t
。
size_t
from cstddef
が同じであり、常に他のものと同じであるという保証はありますか?size_t
...のような一般的な定義を持つ一般的なヘッダーファイルがあるはずです
cstddef
です。
<cstddef>
定義するだけの内部ヘッダーを含めることもできますsize_t
。
csttddef
答えではタイプミス?多分 cstddef
意味ですか?
実際、いくつかのヘッダーの概要(C ++標準に含まれています)にはsize_t
、追加のヘッダーだけでなく、特定のタイプも定義されていますsize_t
(<cX>
ヘッダーは、ISO C <X.h>
ヘッダーにすぎないため、Cの標準に基づいており、削除size_t
は示されていません。
C ++標準では、しかし、を意味<cstddef>
の定義についてstd::size_t
したがって、<cstddef>
タイプのみを導入し、関数は導入しないという事実のため、このヘッダーをstd::size_t
使用できるようにします。
いくつか注意してください:
のタイプは、ヘッダーを含めずにstd::size_t
使用して取得できますdecltype
あなたはしている計画は、とにかくあなたのコード内のtypedefを導入する場合(つまり、あなたは、コンテナを作成し、提供したいためsize_type
のtypedefを)あなたはグローバルに使用できるsizeof
、sizeof...
またはalignof
theoseオペレータが戻るので、まったくのヘッダを含めずにあなたのタイプを定義するための演算子をstd::size_t
あたりに標準的な定義とあなたはdecltype
それらに使用することができます:
using size_type = decltype(alignof(char));
std::size_t
std::size_t
引数付きの関数は表示されますが、それ自体はグローバルに表示されません。
暗黙的に宣言されたグローバル割り当ておよび割り当て解除関数
void* operator new(std::size_t);
void* operator new[](std::size_t);
void operator delete(void*);
void operator delete[](void*);
導入しないsize_t
、std
またはstd::size_t
と
適切なヘッダーを含めることによって名前が宣言されていない限り、参照
std
またはstd::size_t
不正な形式です。
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
std
重複は違法であるため、typedefの再定義の追加が無効であるとは主張しません。私はそれが合法であるnamespace std
かどうかに関係なく、あなたが単に定義を追加しないかもしれないので、それは違法であると述べます。
すべての標準ライブラリヘッダーファイルの定義は同じです。自分のコードにどのコードを含めるかは関係ありません。私のコンピューターでは、に次の宣言があり_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
size_t
そもそもなぜ必要なのですか?
size_t
。より移植性の高いとして定義できますusing size_t = decltype( sizeof( 42 ) )
。しかし、<stddef.h>
ほとんどコストがかからないので、必要はありません。
ヘッダーなしで行うことができます:
using size_t = decltype(sizeof(int));
using size_t = decltype(sizeof 1); // The shortest is my favourite.
using size_t = decltype(sizeof "anything");
これは、C ++標準では次の要件があるためです。
sizeof
and の結果は、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つの単純な宣言として書き留める方法があります。
size_t
です!」1分後、メアリーは言った、「OMG!size_t
標準ライブラリヘッダー全体で7つの定義があり、トムが編集しているプロジェクトヘッダーがある!サードパーティのライブラリにはおそらくもっとある!」xkcd.com/927
size_t
これはの可能な定義ですが、これはOPの実際の質問には答えません。つまり、FILE
宣言されているヘッダーを要求したかのようになり、独自のヘッダーを作成することをお勧めします。