在 Objective-C 中使用 std::shared_ptr 作为全局变量

Use a std::shared_ptr as a global variable in Objective-C

本文关键字:ptr 全局变量 shared std Objective-C      更新时间:2023-10-16

我正在尝试从我的c ++ .h文件与shared_ptr:s一起实现一个类。

为什么我的shared_ptr (totPtr) 在方法之间不保留其值?

当我使用双精度而不是类时的示例代码:

#include <memory>
static std::shared_ptr<myCppClass> totPtr;
static double tot; 

@implementation ViewController

- (void) createSelf
{
    totPtr = std::make_shared<myCppClass>(5); 
    tot = 10;   
}

此方法在创建自我之后调用:

- (void)otherMethod 
{
    tot += 1; // works, tot = 11
    totPtr->doStuff(); // doesn't work, totPtr = nullptr 
}

tot2 的值 = 0,但 tot 的值 = 10

对于全局变量,您应该在 +[initialize] 中初始化它,这是初始化任何全局变量的线程安全方法

+ (void)initialize {
    if (self == [ViewController self]) { // need to guard it so not get called again from subclass
        totPtr = std::make_shared<MyClass>();
        tot = 10;
    }
}

如果你在 viewDidLoad 中初始化它们,它现在可以工作了,但是当你决定有多个ViewController实例时,你会发现第二次调用viewDidLoad将重置这些全局变量。

通常你不想要全局变量,你想要实例变量/属性

@interface ViewController ()
@property (nonatomic) double tot;
@end
@implementation ViewController {
    std::shared_ptr<myCppClass> _totPtr;
}

您可以在另一个答案中描述的viewDidLoad启动它们。

注意:我不建议将 ObjC 属性与类一起使用C++(即 shared_ptr )。因为每次通过属性访问它时,它都需要调用可能需要复制shared_ptr的setter/getter方法的开销,这是一个扩展操作(您应该始终在方法参数中通过引用传递shared_ptr,但这在ObjC中没有很好的支持)。直接访问 ivar 可以避免开销。

最好不要使用全局变量 - 最好使用属性。

但是如果你仍然需要它 - 不要对它使用 init 方法。

在您的代码上,我没有看到谁在调用 createSelf 方法。

在这里,我显示了工作代码。

#import "ViewController.h"
#import "MyClass.h"
#include <memory>
static std::shared_ptr<MyClass> totPtr;
static double tot;
@interface ViewController ()
@property (nonatomic) std::shared_ptr<MyClass> p1;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    [self m1];
    [self m2];
    // Do any additional setup after loading the view, typically from a nib.
}
-(void) m1{
    totPtr = std::make_shared<MyClass>();
    self.p1 = std::make_shared<MyClass>();
    tot = 10;
}
-(void) m2{
    NSLog(@"id: %d",self.p1->id());
    NSLog(@"id: %d",totPtr->id());
}
- (IBAction)ev1:(id)sender {
    [self m2];
}
@end

更新:

如果要在 init* 方法中初始化该变量,可以使用此方法

- (instancetype)initWithCoder:(NSCoder *)coder*