我正在将一个项目移植到 iPhone(来自 Windows Mobile),并使用 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 Window 的应用程序默认提供的。(我通过删除 .xib 删除了 Interface Builder,从 MemoryTest-Info.plist 中删除了“主 nib 文件基本名称”,并将 @“MemoryTestAppDelegate”指定为 main.mm 中 UIApplicationMain 的第四个参数。)
模拟器按预期运行此示例,但设备出现了我的问题:单步执行 applicationDidFinishLaunching 中的代码,Widget 对象按预期构建。但是,wideHello 和 narrowHello 在 Locals 观察区域中似乎都已损坏。(wideHello 不显示,但显示了正确的字符数,narrowHello 显示为“`K3\x10f\x11”。)检查内存窗口中的两个字符串,可以看到正确的内容 - 超出假定地址 64 个字节wideHello 和narrowHello 的。
如对重载方法 Widget::Go(const wchar_t*) const 的第二次调用所示,wideHello 字符串通过 std::wcout 显示,并且在单步执行 applicationDidFinishLaunching 时正确输出字符串!但是,使用 wcscpy/memcpy 从实际内容前 64 字节的“pre”数据中读取的复制操作会导致我在实际设备上的应用程序出现许多问题。如果我用 Widget* 和动态分配替换在本地堆栈上初始化 Widget,则内存布局符合预期。我尝试了其他变体,但似乎只有堆栈分配的 C++ 对象会导致问题。
任何信息将不胜感激,感谢阅读。