Я портирую проект на iPhone (из Windows Mobile) и делюсь большей частью общего кода C и C ++, насколько это возможно, используя Objective-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 на базе Windows. (Я удалил Interface Builder, удалив файл .xib, удалив «Основное имя файла основного пера» из MemoryTest-Info.plist и указав @ «MemoryTestAppDelegate» в качестве 4-го параметра для UIApplicationMain в main.mm.)
Симулятор запускает этот пример, как и ожидалось, но устройство представляет мою проблему: пошагово просматривая код в applicationDidFinishLaunching, объект Widget создается, как и ожидалось. Тем не менее, WideHello и thinHello оба, кажется, повреждены в области наблюдения местных жителей. (wideHello не отображается, но указывается правильное количество символов, а smallHello отображается как "` K3 \ x10f \ x11 ".) Изучая две строки в окне памяти, отображается правильное содержимое - 64 байта за пределами предполагаемого адреса из широкого Привет и узкого Привет.
Как показывает второй вызов перегруженного метода, Widget :: Go (const wchar_t *) const, строка wideHello отображается через std :: wcout, и после перехода через applicationDidFinishLaunching строка выводится правильно! Тем не менее, операции копирования с использованием wcscpy / memcpy читают из «предварительных» данных на 64 байта раньше фактического содержимого, что вызывает много проблем для моего приложения на реальном устройстве. Если я заменим инициализацию виджета в локальном стеке на виджет * и динамическое выделение, расположение памяти будет таким, как ожидалось. Я пробовал другие варианты, но только объекты C ++, выделенные в стеке, похоже, вызывают проблему.
Любая информация будет принята с благодарностью, спасибо за чтение.