4

コードで使用するメモリをできるだけ少なくしようとしています。カスタム クラス オブジェクトをメソッドに送信する 2 つの方法を試しました。これら2つのアプローチに違いがあるかどうかはわかりません。もちろん、それぞれ独自のクラス変数とメソッドを持つClass1Class2の 2 つのクラスがあるとします。

すべてのコードはClass1で書かれています

アプローチ 1:

Class2 *class2Object = [[Class2 alloc] init];

[self doSomething: class2Object];

[class2Object release];

-(void) doSomething: (Class2 *) var {
int a = var.a;
}

アプローチ 2:

Class2 *class2Object = [[Class2 alloc] init];

[self doSomething: &class2Object];

[class2Object release];

-(void) doSomething: (Class2 **) var {
int a = var->a;
}

これら 2 つの方法にパフォーマンスの違いはありますか? 2 番目のアプローチはまったく無意味ですか? アプローチ 1 ではドット表記を使用できるのに、アプローチ 2 では -> を使用する必要があるのはなぜですか?

ありがとう。

4

3 に答える 3

4

アプローチ 1 では、 という名前のプロパティにアクセスしていますa。これは問題ないようです。

アプローチ 2 では、コードがコンパイルされることにショックを受けました。へのポインターを渡すこともまったく役に立ちませんclass2Object。オブジェクトにポインターを渡す唯一の理由は、呼び出されたメソッドがそのパラメーターを更新する必要がある場合 (たとえば、それが out-parameter の場合) ですが、ここではそうではありません。オブジェクトへのポインターを渡すことは、メモリ使用量にはまったく影響しません。オブジェクトは既にポインターとして保持されているため (これが を記述する理由ですClass2 *)、C++ でスタック割り当てオブジェクトを渡すときに見られるようなオブジェクトのコピーのオーバーヘッドはありません (Obj-C にはスタック割り当てオブジェクトの概念がありません)。 、心配する必要がない奇妙なコーナーケースであるブロックを除いて)。

基本的に、ここではアプローチ 1 を使用します。

于 2011-11-14T18:37:17.000 に答える
4

これら 2 つの方法にパフォーマンスの違いはありますか?

実際、アプローチ 2 ではもう 1 つの間接参照 (つまり、ポインターの逆参照、以下も参照) があるため、パフォーマンスの差はごくわずかです。したがって、アプローチ 1 を使用すると、数クロック サイクルを節約できます。

2 番目のアプローチはまったく無意味ですか?

アプローチ 2 は、Class2 型の新しいインスタンスを割り当てて、同じ引数を介して呼び出し元に戻したい場合などに便利です。いう:

 - (bool)cloneObject:(Class2 **)var;

オブジェクトを渡します。オブジェクトは複製され、var に返されます。変更されるのはオブジェクト自体のアドレスであるため、新しいアドレスを設定するには、オブジェクトへのポインターへのポインターが必要です。戻り値は、操作が正しく実行されたかどうかのみを示します。

もちろん、この例では、次のようにする方がより自然です。

     - (Class2)cloneObject:(Class2*)var;

つまり、新しく割り当てられたオブジェクトへのポインターを返しますが、ユースケースは引き続き保持されます。

アプローチ 1 ではドット表記を使用できるのに、アプローチ 2 では -> を使用する必要があるのはなぜですか?

2 番目のケースでは->、オブジェクトへのポインターを直接扱っていないため、使用する必要があります。オブジェクトへのポインターへのポインターを扱っています。このような場合に必要なことは、まず、オブジェクトへのポインターを取得するためにポインターを「逆参照」し (つまり、演算子 * を適用して)、それから他の方法で後者にアクセスすることです。これは次のように書くことができます:

 (*var).a

ここで、varは のオブジェクトへのポインターへのポインターClass2です。*varはそれを逆参照した結果なので、のオブジェクトへのポインターがありますClass2。最後に.a、オブジェクト プロパティにアクセスするための構文です。構文:

var->a

上記の操作の単なる「省略形」です。

于 2011-11-14T18:58:22.537 に答える
2

x->yCの構文はと同じ(*x).yであるため、他の人が言っているように、余分な(不要な)ポインターの取得と逆参照を除いて、実行内容に違いはありません。しかし、もっと興味深い関連点について詳しく説明したいと思います。

あなたはそれを理解する必要があります

-(void) doSomething: (Class2 *) var {
   int a = var.a;
}

ドットはプロパティアクセスです。var(はポインタであるため、構造体フィールドへのアクセスにすることはできません。)これは(ゲッターが別のメソッドに明示的に設定されていない限り)とまったく同じです。int a = [var a];

すべてのメソッド呼び出しと同様に、動的メッセージパッシングメカニズムを通過します。そのわずかなオーバーヘッドを回避したい場合は、変数に直接アクセスできる可能性があります。

プロパティaがインスタンス変数から合成されている場合a(別の名前で呼ばれている可能性がありますがa、ここで説明します)、プロパティを介して変数にアクセスする代わりに、パブリックとして宣言できます(@public;を使用しない場合、インスタンス変数はデフォルトで保護されます)。次に、次の方法で直接アクセスします->

-(void) doSomething: (Class2 *) var {
   int a = var->a;
}

var(これは、オブジェクトポインター自体であり、ポインターへのポインターではないため、現在のポインターとは異なることに注意してください。)

ただし、パブリックインスタンス変数は一般的に悪いスタイルと見なされ、推奨されません。これを使用すると、オブジェクト指向プログラミングの抽象化が破られます。技術的にはインスタンス変数にアクセスする「最速の」メソッドであるため、完全を期すためにここで取り上げます。

于 2011-11-14T23:38:46.373 に答える