2

githubにサンプルプロジェクトがあり、Objective-Cで使用する外部C++ライブラリのc++ラッパークラスを作成しました。

返されたポインタが正しい場合と間違っている場合がある理由がわかりません。出力例は次のとおりです。

Test Data = 43343008
In Compress 43343008
Returned Value = 43343008
Casted Value = 43343008

Test Data = 2239023
In Compress 2239023
Returned Value = 2239023
Casted Value = 2239023

Test Data = 29459973
In Compress 29459973
Returned Value = 29459973
Casted Value = l.remote

Test Data = 64019670
In Compress 64019670
Returned Value = 
Casted Value = stem.syslog.master

上記の出力では、ボタンの1回目と2回目のクリックで、期待した結果が出力されていることがわかります。他の各クリックでは、戻り値またはキャスト値のいずれかが無効です。これは、ポインタが予期していなかったアドレスを指しているためだと思います。アプリを複数回実行する場合、ボタンのクリックは正しいか間違っている可能性があります。

私もシングルスレッドで試しましたが、同様の結果が得られました。

完全なコードはgithubにありますが、ここに重要な部分があります。

ViewController.m

#import "ViewController.h"

extern const char * CompressCodeData(const char * strToCompress);

@implementation ViewController

...

// IBAction on the button
- (IBAction)testNow:(id)sender 
{
    [self performSelectorInBackground:@selector(analyze) withObject:nil];
}

- (void)analyze
{
    @synchronized(self) {

        const char *testData = [[NSString stringWithFormat:@"%d", 
                      (int)(arc4random() % 100000000)] UTF8String];
        NSLog(@"Test Data = %s", testData);

        const char *compressed = CompressCodeData(testData);
        NSLog(@"Returned Value = %s", compressed);

        NSString *casted = [NSString stringWithCString:compressed
                                          encoding:NSASCIIStringEncoding];
        NSLog(@"Casted Value = %@\n\n", casted);

    }
}

@end

SampleWrapper.cpp

#include <iostream>
#include <string.h>
#include <CoreFoundation/CoreFoundation.h>

using namespace std;

extern "C" 
{
    extern void NSLog(CFStringRef format, ...); 

    /**
     * This function simply wraps a library function so that 
     * it can be used in objective-c.
     */
    const char * CompressCodeData(const char * strToCompress) 
    {
        const string s(strToCompress);

        // Omitted call to static method in c++ library
        // to simplify this test case.

        //const char *result = SomeStaticLibraryFunction(s);
        const char *result = s.c_str();

        NSLog(CFSTR("In Compress %s"), result);
        return result;
    }

}
4

1 に答える 1

4

割り当てが解除されたオブジェクトへのポインタを返しています。

const string s(strToCompress);
…
const char *result = s.c_str();

NSLog(CFSTR("In Compress %s"), result);
return result;

s関数が終了した後は存在しないCompressCodeData()ため、その内部メモリへのポインタは無効です。


応答を保持するためにメモリのチャンクを割り当てることもできますが、それを解放するのは呼び出し元の責任です。

char *compressed = CompressCodeData(testData);
NSLog(@"Returned Value = %s", compressed);

NSString *casted = [NSString stringWithCString:compressed
                                      encoding:NSASCIIStringEncoding];
free(compressed);
NSLog(@"Casted Value = %@\n\n", casted);

…

const char * CompressCodeData(const char * strToCompress)
…
char *result = strdup(s.c_str());

別の解決策は、データを格納するためにメモリを渡すことです。

char compressed[2048]; // Or whatever!
CompressCodeData(testData, compressed, sizeof(compressed));
NSLog(@"Returned Value = %s", compressed);

NSString *casted = [NSString stringWithCString:compressed
                                      encoding:NSASCIIStringEncoding];
NSLog(@"Casted Value = %@\n\n", casted);

…

void CompressCodeData(const char * strToCompress, char *result, size_t size)
…
s.copy(result, size - 1);
result[s.length() < size ? s.length() : size-1] = '\0';
于 2012-06-13T16:57:14.873 に答える