【问题标题】:Memory Leak using C style Function in Objective C在 Objective C 中使用 C 风格函数的内存泄漏
【发布时间】:2010-06-25 12:24:24
【问题描述】:

如果我声明一个函数,例如:

NSString* createAString(std::string toConvert);

NSString* createAString(std::string toConvert)
{
      return [NSString stringWithUTF8String:toConvert.c_str()];
}

我的印象是,因为我没有在字符串上调用 alloc,所以它会在自动释放范围内。

当我运行此代码时,XCodes 内存泄漏检测器告诉我从这一点开始存在内存泄漏。我不能以这种方式混合 C 风格的函数和 Objective C 类型吗?还是手头有更多的基本问题?

干杯 斯图贝尔

【问题讨论】:

    标签: iphone objective-c memory-management


    【解决方案1】:

    您的代码没有问题。您可以在 Objective-C 代码中混合 C 风格的函数。我没有看到 Obj-C 对象的保留/释放有任何问题,C++ 对象的新建/删除也没有。

    但是你的函数名违反了Create Rule。即,如果函数或方法的名称包含 alloccreatecopy,则假定返回 NSObjectCF 保留计数为 1 的对象。XCode 静态分析器在此假设下工作规则。您还应牢记此规则。否则保留/释放会搞砸。

    尝试构建并分析此文件。

    #import <CoreFoundation/CoreFoundation.h>
    
    extern CFStringRef FooCreate(void);
    int main (int argc, const char * argv[]) {
        CFStringRef string=FooCreate();
        /* CFRelease(string); */
        return 0;
    }
    

    如果您(取消)评论CFRelease,您可以看到分析器更改的结果。您不必提供FooCreate 的定义。即使您确实提供了,当前的分析器也不会查看它,而是依赖于函数名称。

    即使方法名称中包含create,您的代码也会返回一个自动释放的变量。这可能会使分析器产生误报。

    【讨论】:

    • 分析器肯定不会看函数名来检测泄漏!
    • 什么??当然可以。我不是在谈论泄漏工具,而是在谈论静态分析器。我在答案中添加了一个示例;请使用最新的分析仪自己尝试一下。
    • +1 除了“创建”规则仅适用于函数,方法。
    • 啊,确实如此。我不知道。是否有任何 Cocoa 方法的选择器 create 在其中?那会完全令人困惑......我需要重新检查我的代码。
    • @Yuji +[UIPasteboard pasteboardWithName:create:] 是我找到的唯一一个。
    【解决方案2】:

    @Yuji 的答案已经死了,而且是正确的答案。

    我只是想指出,与其将其设为 C 函数,不如将其设为“更多 Cocoa”并使用类别:

    //NSString+STDConversion.h
    @interface NSString (STDConversion)
    
    + (NSString *) stringWithStdString:(std::string toConvert);
    
    @end
    
    //NSString+STDConversion.mm (note the .mm extension)
    @implementation NSString (STDConversion)
    
    + (NSString *) stringWithStdString:(std::string toConvert) {
      return [NSString stringWithUTF8String:toConvert.c_str()];
    }
    
    @end
    

    现在你可以在其他地方做:

    std::string myString = "This is my string";
    NSString * myCocoaString = [NSString stringWithStdString:myString];
    

    【讨论】:

      【解决方案3】:

      这段代码对我来说很好。

      很可能在其他地方你有一些代码错误地保留了这个字符串并且以后没有释放它,从而导致泄漏。 XCode 不能告诉你哪里有不匹配的保留/释放,它只能告诉你泄漏对象的来源。

      正如其他人所提到的,您对“create”的使用违反了 Objective-C 的命名规则。您应该将其重命名为 stringFromStdString 或类似名称。对于奖励积分,您可以将其作为 NSString 类的扩展。

      【讨论】:

      • 见我上面的回复;静态分析器会检查函数名称。
      【解决方案4】:

      检查您是否不是从池外调用它(stringWithUTF8String: 使用它)。尝试将其包装在

      NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
          //...
      [pool drain];

      如果它解决了问题,那么你(就像你说的那样)来自范围之外。

      【讨论】:

        【解决方案5】:

        您返回的字符串将被自动释放,但是您传递给方法的(C++)字符串呢?之后你会释放它吗?

        我想到的另一件事是用于执行静态分析的编译器 LLVM 尚不支持 C++(至少在公开发布的版本中不支持)。它可能只是因为没有完全理解某些代码而导致的误报。

        【讨论】:

        • std::string 是栈上的对象,所以它的构造函数和析构函数会被自动调用。他没有使用std::string*。它不像 Obj-C ...
        • 请阅读您的答案。我没有测试过,但它是有道理的。
        猜你喜欢
        • 1970-01-01
        • 2011-06-07
        • 1970-01-01
        • 1970-01-01
        • 2011-06-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多