unionとそのリスク
型間でメモリを共有します
「unionとそのリスク」はCoddyKit上の無料C++ Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC++ Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C++ Academyコースには全4レッスンが含まれています。
union とは
union を使うと、複数のメンバーで同じメモリを共有できます。一度に有効にできるメンバーは 1 つだけで、union のサイズは最大のメンバーと同じになります。
#include <iostream>
union Number {
int i;
float f;
};
int main() {
Number n;
n.i = 42;
std::cout << n.i << "\n";
}union のサイズ
メンバーは重なって配置されるため、union の sizeof はメンバーの合計ではなく、最大のメンバーのサイズ(およびアラインメント用のパディング)になります。
#include <iostream>
union Mix { char c; int i; double d; };
int main() {
std::cout << sizeof(Mix) << "\n"; // size of double (often 8)
}一方に書き込み、別の一方を読み取る
一方のメンバーに書き込み、別のメンバーを読み取ることが、中心的なリスクです。ビットが別の型として解釈されるため、通常は未定義の動作になるか、予想外の結果になります。
#include <iostream>
union Bits { int i; float f; };
int main() {
Bits b;
b.f = 1.0f;
std::cout << b.i << "\n"; // reads float bits as int
}アクティブにできるメンバーは1つだけ
安全に読み取れるのは、最後に書き込んだメンバーだけです。どのメンバーが「アクティブ」かは、ユニオン自身は記憶しないため、自分で管理してください。
#include <iostream>
union Value { int i; double d; };
int main() {
Value v;
v.d = 3.14; // d is active
std::cout << v.d << "\n";
}タグ付きユニオンパターン
ユニオンを安全に使うには、アクティブなメンバーを記録するタグ(enum)と組み合わせます。これはstd::variantの手動実装による先祖にあたります。
#include <iostream>
struct Tagged {
enum { Int, Double } tag;
union { int i; double d; };
};
int main() {
Tagged t; t.tag = Tagged::Int; t.i = 7;
if (t.tag == Tagged::Int) std::cout << t.i << "\n";
}正しいメンバーを読み取る
読み取る前に、必ずタグに基づいて分岐してください。間違ったメンバーを読み取ると、無意味な値が生成されます。
#include <iostream>
struct Tagged {
enum { Int, Double } tag;
union { int i; double d; };
};
void print(const Tagged& t) {
if (t.tag == Tagged::Int) std::cout << "int " << t.i << "\n";
else std::cout << "double " << t.d << "\n";
}
int main() { Tagged t{Tagged::Double}; t.d = 2.5; print(t); }非自明なメンバー
コンストラクターやデストラクターを持つメンバー(std::stringなど)をユニオンに入れるには、手動で構築と破棄を行う必要があります。これはエラーの原因になりやすく、std::variantを優先するもう1つの理由です。
匿名ユニオン
匿名ユニオンには名前がなく、そのメンバーに直接アクセスします。構造体の内部で便利に使えますが、アクティブなメンバーに関する同じルールが適用されます。
#include <iostream>
struct Packet {
int kind;
union { int code; char letter; };
};
int main() {
Packet p; p.kind = 1; p.code = 99;
std::cout << p.code << "\n";
}ユニオンが危険な理由
危険性のまとめ:
- どのメンバーがアクティブかを記憶しません。
- アクティブでないメンバーを読み取ると、未定義の動作になります。
- 非自明な型には、手動でライフタイムを管理する必要があります。
それでもユニオンが役立つ場面
ユニオンは、低レベルの処理では今でも役立ちます。たとえば、バイトの再解釈、組み込みコードでメモリが厳しく制限される場合の節約、固定されたバイナリレイアウトへの対応などです。日常的な「複数の型のうち1つ」を表すデータには、より安全な代替手段を優先してください。
std::variantへ向けて
std::variantは、アクティブな型を自動的に追跡する型安全なユニオンです。間違った型にアクセスすると例外を送出します。このコースの後半では、std::variantについて詳しく学びます。
理解度チェック
ユニオンについての理解を確認しましょう。
まとめ
ユニオンについて、次のことを学びました:
- すべてのメンバーが1つのメモリ領域を共有します。
- 読み取れるのは、最後に書き込んだメンバーだけです。
- タグ(enum)を使って、アクティブなメンバーを追跡します。
- 現代のC++では、安全性のために
std::variantを優先します。
AI チューターと学ぶ C++ — 無料
ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。
- コース
- 51
- レッスン
- 203
よくある質問
「unionとそのリスク」レッスンは無料ですか?
はい。「unionとそのリスク」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C++ Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C++ Academyコースには全4レッスンが含まれています。
「unionとそのリスク」で何を学びますか?
型間でメモリを共有します ブラウザで直接実行するハンズオンコードでC++ Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C++ Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC++ Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「unionとそのリスク」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC++ Academyレッスンでコードを書いて実行できますか?
はい。すべてのC++ Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- スコープ付きenum class
- unionとそのリスク
- std::variant
- std::visit