我最近读到了关于 std::unique_ptr 作为 Objective c 中的 @property 的内容,并且将
unique_ptr
作为属性存储在 ObjC 中的建议如下:
-(void) setPtr:(std::unique_ptr<MyClass>)ptr {
_ptr = std::move(ptr);
}
我的问题是在 ObjC 中,在这种情况下参数是否被复制?因为如果发生这种情况,
unique_ptr
永远不会被宣布为财产权?
我的问题是在 ObjC 中,在这种情况下参数是否被复制?
这要看情况。让我介绍一个自定义类,其中删除了所有复制操作,以更好地演示不同情况下可能的结果:
struct MyClass {
MyClass() {
std::cout << "Default constructor" << std::endl;
}
MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass&) = delete;
MyClass(MyClass&&) {
std::cout << "Move Constructor" << std::endl;
}
MyClass& operator=(MyClass&&) {
std::cout << "Move Assignment" << std::endl;
return *this;
}
};
并相应地更改方法的参数签名:
- (void)setInst:(MyClass)inst {
_inst = std::move(inst);
}
假设示例中的方法属于名为
TDWObject
的类,以下代码将可以正常编译:
[[TDWObject new] setInst:MyClass{}];
在C++17下,你会发现默认的构造函数和移动赋值称为:
Default constructor
Move Assignment
为临时对象调用默认构造函数,并且由于有保证的复制省略,不需要复制或移动构造函数来使用临时对象初始化方法的参数
inst
。移动分配很简单 - 它发生在分配 std::move(inst)
操作的结果时。如果您使用 C++11 或 C++14,标准不保证复制省略,但 clang 无论如何都会这样做。一些编译器使用 move-semantic 来代替,但总体来说,这段代码暂时应该可以正常工作。
另一个选项是将任何命名变量转换为右值,它仍然允许初始化参数而不会出现任何问题:
MyClass inst;
[[TDWObject new] setInst:std::move(inst)];
这种情况的区别在于,函数参数实际上会调用移动构造函数,而没有省略优化:
Default constructor
Move Constructor
Move Assignment
这是破碎的场景:
TDW::MyClass inst;
[self setInst:inst];
这当然不行,因为参数需要调用复制构造函数,该构造函数被标记为已删除。好处是,这段代码永远不会编译,你会立即发现问题。
首先,我真的不认为 Objective-C 属性与不可复制的 C++ 类兼容,并决定对链接的问题给出我自己的答案,您可以在here查看。
我不希望代码编译为
ptr
在那里按值传递。
更好的是:
-(void) setPtr:(std::unique_ptr<MyClass>) &&ptr {
_ptr = std::move(ptr);
}
编辑:想一想,这也可能无法编译。我不知道 Objective_C 是否理解通过引用、右值或其他方式传递参数。但如果没有,这应该有效:
-(void) setPtr:(std::unique_ptr<MyClass>) *ptr {
_ptr = std::move(*ptr);
}