1

一部のObjective-Cコードを、GCCの「式のステートメントと宣言」拡張機能 を多用するARCに変換しています({})

GCC拡張機能は、Objective-Cオブジェクトを作成するためにプリプロセッサマクロで使用されています。実際のマクロはかなり複雑なので、これは物事を単純化するために考案された例です。_x私の例では、パラメータは常にNSString *次のようになっていると仮定します。

#define f(_x) ({ NSString *x = (_x); [NSString stringWithString: x]; })

もちろん、このマクロは次のように呼び出されます。

void foo() { NSString *s = f(@"foo"); }

ARC以前の環境では、これは問題なく機能します。呼び出しによって作成されたオブジェクトstringWithString:は自動解放されたオブジェクトであり、GCC拡張機能はそれをに割り当てますs

ただし、ARC(Xcode 4.4.1)に変換した後、ステートメントブロックが終了するとすぐにオブジェクトが解放されます(これは、オブジェクトをインスタンス化することで確認しましたNSLog()dealloc

次のようなタイプキャストでマクロを変更してみました。

#define f(_x) ({ NSString *x = (_x); (__autoreleasing id) [NSString stringWithString: x]; })

#define f(_x) ({ NSString *x = (_x); (NSString __autoreleasing *) [NSString stringWithString: x]; })

ただし、どちらの形式でもコンパイルエラーが発生します。

Explicit ownership qualifier on cast has no effect

その場合、ARCとこのGCC拡張機能には互換性がないように見えます。

これはそうですか、それとも、ARCにオブジェクトをすぐに解放しないように指示する単純なものがありませんか?

私にはいくつかのオプションがあります。現時点で最も魅力的なのは、これらすべてのマクロを__inline__関数に変換することですが、処理するコードはかなりあります。私は本当に迅速な修正を望んでいるので、どんなアイデアでもありがたいです。

4

4 に答える 4

1

私はこれを数時間デバッグしていて、解決策を見つけたので、私自身の質問に答えます。FWIW私はCRDに同意し、それはバグだと思います。Appleにレポートを提出します。

たまたま、私の質問を補った「工夫された例」が実際に機能します(doh)。最初に述べたように、私が使用しているマクロははるかに複雑ですが、そうではありません。ただし、ステートメントブロックの最後のステートメントとして、一時的に作成されたオブジェクトを返すと、それら返されることを発見しました。そのように書かれた場合、ARCはオブジェクトを解放しません。clangには非常に狭いRVOタイプのコードがあり、ARCパーサーと衝突していると思います。

とにかく、回避策は次のようになります(行の最後までスクロールします)。

#define f(_x) ({ NSString *x = (_x); NSString *y = [NSString stringWithString: x]; y; })
于 2012-09-20T11:01:26.677 に答える
1

興味深い観察結果は、定義されたセマンティクスと明らかに矛盾するため、コンパイラのバグレポートに値する可能性があります。

割り当てをマクロに移動できます。

#define f(lhs, _x) ({ NSString *x = (_x); lhs = [NSString stringWithString: x]; })

これでリリースの問題が解決するはずです。しかし、インライン関数に切り替える方がおそらく良いでしょう!

于 2012-09-20T10:29:40.923 に答える
0

問題は、{}内のNSString*xが{}外で定義されていないことです。したがって、後で参照することはできず、ARCがリリースするのは正しいことです。{}ブロックの戻り値は私の目には定義されていないため、マクロはそもそも機能しないはずです。

これはトリックを行う必要があります

#define f(_x) (NSString *x = (_x); [NSString stringWithString: x]

ただし、名前を付けたり、複数のステートメントであるために、副作用が発生する可能性があります。

インライン関数を使用することは、より論理的な方法です。

于 2012-09-20T08:40:30.293 に答える
0

PS:({})がGCC固有のマクロ拡張機能である場合、私は完全には認識していません。Appleは現在GCCではなくclangをデフォルトとして使用していることに注意してください。

于 2012-09-20T08:48:01.597 に答える