プロジェクトを (Windows Mobile から) iPhone に移植し、Objective-C++ を使用して、汎用の C および C++ コードの多くを可能な限り共有しています。ただし、テスト中に、デバイスで実行している場合にのみ現れる、好奇心旺盛で厄介な問題に遭遇しました。再現性を証明し、簡単に共有できるように、問題のコードを新しいプロジェクトにまとめました。
// MemoryTestAppDelegate.mm
#include "MemoryTestAppDelegate.h"
#include "Widget.h"
@implementation MemoryTestAppDelegate
@synthesize window;
- (void)applicationDidFinishLaunching: (UIApplication*)application {
Widget widget;
const wchar_t wideHello[] = L"Hello, world!";
const char narrowHello[] = "Hello, world!";
widget.Go();
widget.Go(wideHello);
[window makeKeyAndVisible];
}
- (void)dealloc {
[window release];
[super dealloc];
}
@end
// MemoryTestAppDelegate.h
#import <UIKit/UIKit.h>
@interface MemoryTestAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow* window;
}
@property (nonatomic, retain) IBOutlet UIWindow* window;
@end
// Widget.h
#include <iostream>
class Widget {
public:
Widget() { };
~Widget() { };
void Go() const { std::wcout << L"Widget is GO." << std::endl; };
void Go(const wchar_t* message) const { std::wcout << message << std::endl; };
};
// main.mm
#import <UIKit/UIKit.h>
int main(int argc, char* argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, @"MemoryTestAppDelegate");
[pool release];
return retVal;
}
残りのプロジェクト ファイルと設定は、新しい iPhone ウィンドウ ベースのアプリケーションを作成することによってデフォルトで提供されます。(.xib を削除し、MemoryTest-Info.plist から「メイン nib ファイルのベース名」を削除し、main.mm で UIApplicationMain の 4 番目のパラメーターとして @"MemoryTestAppDelegate" を指定して、Interface Builder を削除しました。)
シミュレーターはこの例を期待どおりに実行しますが、デバイスには問題があります。ただし、wideHello と wideHello の両方が Locals ウォッチ エリアで破損しているように見えます。(wideHello は表示されませんが、正しい文字数が示され、narrowHello は "`K3\x10f\x11" と表示されます。) メモリ ウィンドウで 2 つの文字列を調べると、正しい内容が表示されます - 想定されたアドレスを 64 バイト超えています。 wideHelloとnarrowHelloの
オーバーロードされたメソッド Widget::Go(const wchar_t*) const の 2 番目の呼び出しで示されるように、wideHello 文字列は std::wcout を介して表示され、applicationDidFinishLaunching をステップ実行すると、文字列が正しく出力されます。ただし、wcscpy/memcpy を使用したコピー操作は、実際のコンテンツの 64 バイト先の「前の」データから読み取られたため、実際のデバイス上のアプリケーションに多くの問題が発生しました。ローカル スタック上のウィジェットの初期化を Widget* と動的割り当てに置き換えると、メモリ レイアウトは期待どおりになります。他のバリエーションも試しましたが、スタックに割り当てられた C++ オブジェクトだけが問題を引き起こしているようです。
読んでくれてありがとう。