不透明なポインタ
コンピュータ プログラミングにおいて、不透明ポインタは不透明データ型の特殊なケースであり、不特定の型のレコードまたはデータ構造へのポインタとして宣言されたデータ型です。
不透明ポインタは、 Ada、C、C++、D、Modula-2などのいくつかのプログラミング言語に存在します。
使用
ポインタが実装されている言語が強い型付け言語である場合、不透明なポインタ型Tに関する他の情報を持たないプログラムや手続きでも、 T型の変数、配列、レコードフィールドを宣言し、その型の値を代入し、それらの値の等価性を比較することができます。ただし、そのようなポインタを逆参照することはできず、不足している情報を持つ何らかの手続きを呼び出すことによってのみ、オブジェクトの内容を変更することができます。
不透明ポインタは、インターフェースの実装の詳細を一般のクライアントから隠蔽する方法です。これにより、インターフェースを使用するモジュールを再コンパイルすることなく実装を変更できます。これは、シンプルなインターフェースを作成し、ほとんどの詳細を別のファイルに隠蔽できるため、プログラマにとってもメリットがあります。[1]これは、例えば共有ライブラリの異なるバージョン間でバイナリコードの互換性を確保するために重要です。
この手法はデザインパターンではブリッジパターンとして説明されています。特にC++コミュニティでは、「ハンドルクラス」[2] 、 「Pimplイディオム」(「実装へのポインタイディオム」の略)[3] 、 「コンパイラファイアウォールイディオム」[4] 、 「dポインタ」 、あるいは「チェシャ猫」と呼ばれることもあります。[2]
例
エイダ
パッケージ Library_Interface は 型 ハンドルは 限定プライベートです 。 -- オペレーション...private type Hidden_Implementation ; -- パッケージ本体で定義された type Handle は、 アクセス Hidden_Implementation ;であり、 Library_Interface の終了です 。この型はHandle、仕様では定義されていない実際の実装への不透明なポインタです。この型はプライベート(クライアントが型に直接アクセスすることを禁止し、操作を通じてのみアクセスできるようにするため)であるだけでなく、制限付き(データ構造のコピーを回避し、ダングリング参照を防ぐため)であることにも注意してください。
パッケージ 本体の Library_Interface は type Hidden_Implementation is record ... -- 実際の実装は何でも構いません end record ; -- 操作の定義... Library_Interface を終了します。これらのタイプは、Ada 83のいわゆる「タフト修正条項」で導入されたため、Ada 95の主な設計者であるタッカー・タフトにちなんで「タフトタイプ」と呼ばれることもあります。 [5]
C
Integer.hの場合:
#プラグマワンスtypedef struct Integer整数; /* * コンパイラはstruct objを不完全型とみなします。不完全型は宣言で使用できます。*/size_t整数サイズ( void ); void integerSetValue (整数* 、int ); int integerGetValue (整数* ); Integer.cの場合:
#include "Integer.h" typedef struct Integer { int値; }整数; /* * 呼び出し側が割り当てを処理します。* 必要な情報のみを提供します*/size_t integerSize ( void ) { sizeof ( Integer )を返します。 } void integerSetValue ( Integer * i , int val ) { i -> value = val ; } int integerGetValue (整数* i ) {戻り値i ->値; } この例は、C言語を用いてオブジェクト指向プログラミングにおける情報隠蔽(カプセル化)の側面を実現する方法を示しています。 の定義を変更したい場合、 APIも変更されない限り、プログラム内でヘッダーファイルを使用する他のモジュールを再コンパイルする必要はありません。関数は渡されたポインタが ではないことを確認することが望ましい場合もありますが、簡潔にするためにそのような確認は省略されています。struct IntegerInteger.hNULL
C++
MyClass.cppm内:
モジュールorg.example.MyClassをエクスポートします。 stdをインポートします。 std :: unique_ptrを使用します。 エクスポート名前空間org :: example { class MyClass { private : struct IntPair ; // ここでは定義されていませんunique_ptr < IntPair > ptr ; // 不透明ポインタpublic : MyClass (); // コンストラクタMyClass ( const MyClass & ); // コピーコンストラクタMyClass ( MyClass && ); //移動コンストラクタMyClass & operator = ( const MyClass & ); // コピー代入演算子MyClass & operator = ( MyClass && ); // 移動代入演算子~ MyClass (); // デストラクタ // その他の操作... };}MyClass.cppの場合:
モジュールorg.example.MyClass ; 名前空間org ::例{ 構造体MyClass :: IntPair { int a ; int b ; }; MyClass :: MyClass () : ptr { std :: make_unique <IntPair> ( ) } {} MyClass :: MyClass ( constMyClass & other ) : ptr { std :: make_unique <MyClass> ( * other.ptr ) } { } MyClass :: MyClass ( MyClass && other ) =デフォルト; MyClass & MyClass :: operator = ( const MyClass & other ) { * ptr = * other . ptr ; return * this ; } MyClass & MyClass ::演算子= ( MyClass && ) =デフォルト; MyClass ::~ MyClass () =デフォルト; }不透明なポインタ
dポインタパターンは、不透明ポインタの実装の一つです。C++クラスでは、その利点(後述)から広く用いられています。dポインタは、構造体のインスタンスを指すクラスのプライベートデータメンバーです。この手法により、クラス宣言において、dポインタ自身を除くプライベートデータメンバーを省略することができます。[6]その結果、
- クラスの実装の多くは隠されています
- プライベート構造に新しいデータメンバーを追加してもバイナリ互換性には影響しません。
- クラス宣言を含むヘッダー ファイル /interface module には、クラスの実装ではなく、クラス インターフェイスに必要なファイルのみを含める必要があります。
副次的な利点としては、ヘッダーファイル/インターフェースモジュールの変更頻度が低いため、コンパイルが高速化されるという点が挙げられます。ただし、dポインタパターンのデメリットとして、ポインタを介した間接的なメンバーアクセス(例えば、動的ストレージ内のオブジェクトへのポインタ)が挙げられます。これは、ポインタではない単純なメンバーへのアクセスよりも遅くなる場合があります。dポインタはQt [7]やKDEライブラリで頻繁に使用されています。
「ポインタと乱数とのXOR演算」を行うと、結果は「非常に不透明な」ポインタとなり、メモリ位置が暗号化されてユーザーによるアクセスを阻止します。[8] [9] [10]
参照
参考文献
- ^ Chris McKillop. 「プログラミングツール — 不透明ポインタ」. QNXソフトウェアシステム. 2021年11月12日時点のオリジナルよりアーカイブ。 2019年1月16日閲覧。
- ^ ab Eckel, Bruce (2000). 「第5章 実装の隠蔽」. Thinking in C++ . 第1巻 標準C++入門(第2版). Prentice Hall. ISBN 0-13-979809-9。
- ^ バトフ、ウラジミール (2008-01-25)。 「ニキビを簡単に作る」。ドブ博士の日記。2008 年 5 月 7 日に取得。
- ^ Sutter, Herb (2009) [1998年7-8月]. 「Pimplsの喜び(あるいは、コンパイラ・ファイアウォール・イディオムについて)」. C++ Report . 第10巻、第7号. 2025年9月16日閲覧– gotw.ca経由。 [リンク先] 初出時のほぼ原文のまま。最新版は書籍
『Exceptional C++』
(2000年、Addison-Wesley刊)
に掲載。
{{cite magazine}}: CS1 maint: url-status (リンク) - ^ Robert A. Duff (2002年7月29日). "Re: What's its name again?".ニュースグループ: comp.lang.ada. 2009年7月29日時点のオリジナルよりアーカイブ。2007年10月11日閲覧。
- ^ 「dポインタの使用」。C ++におけるバイナリ互換性の問題。ポリシー。2024年6月14日。 2025年9月16日閲覧– kde.org経由。
{{cite web}}: CS1 maint: url-status (リンク)— KDEが不透明ポインタを実装する理由と方法 - ^ "d-Pointer". Qt wiki . 2016年12月23日閲覧。
- ^ Howard, Michael (2006年1月30日). 「ポインターの裏技から守る(ちょっと!)」 (ブログ) . 2025年9月16日閲覧– learn.microsoft.com経由。
{{cite web}}: CS1 maint: url-status (リンク) - ^ Drepper, U. (2007年1月24日). 「ポインター暗号化」(ブログ). 2025年9月16日閲覧– udrepper.livejournal.com経由。
…FC6のセキュリティ新機能。
{{cite web}}: CS1 maint: url-status (リンク) - ^ Batov, Vladimir (2008年1月25日). 「Making Pimpl easy」. Dr. Dobb's Journal . 2024年11月20日時点のオリジナルよりアーカイブ。 2025年9月16日閲覧– ddj.com経由。Pimpl
テクニックは、結合を最小限に抑え、インターフェースと実装を分離するのに便利な方法です。
外部リンク
- 「The Pimpl イディオム」。
- 「コンパイル ファイアウォール」。または、Sutter, Herb.「コンパイルファイアウォール」。
- 「高速なPimplイディオム」。
- 「d-Pointers] — KDE TechBase」。