I recently read about a std::unique_ptr as a @property in objective c and the suggestion to store a unique_ptr
in ObjC as a property is as following:
-(void) setPtr:(std::unique_ptr<MyClass>)ptr {
_ptr = std::move(ptr);
}
My question is in ObjC, does the parameter get copied in this case? Because if that happens, unique_ptr
shall never be declared as a property right?
My question is in ObjC, does the parameter get copied in this case?
That depends. Let me introduce a custom class where all copy operations are removed to better demonstrate possible outcomes under different circumstances:
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;
}
};
And change the parameter signature of your method accordingly:
- (void)setInst:(MyClass)inst {
_inst = std::move(inst);
}
Assuming the method in the sample belongs to a class named TDWObject
the following code will compile just fine:
[[TDWObject new] setInst:MyClass{}];
Under C++17, you will find the default constructor and the move assignment called:
Default constructor
Move Assignment
The default constructor is called for the temporary, and thanks to guaranteed copy elision, neither copy nor move constructor is needed to initialise the parameter inst
of the method with the temporary. The move assignment is straightforward - it happens when assigning result of std::move(inst)
operation. If you use C++11 or C++14, standard doesn't guarantee copy elision, but clang will do it anyway. Some compilers use move-semantic instead, but overall for a temporary this code should work just fine.
Another option is to cast any named variable to an rvalue, and it will still allow to initialise the parameter without any issues:
MyClass inst;
[[TDWObject new] setInst:std::move(inst)];
The difference in this case, is that the function parameter will actually call the move constructor without elision optimisation:
Default constructor
Move Constructor
Move Assignment
And here is the broken scenario:
TDW::MyClass inst;
[self setInst:inst];
This will not work of course, because the parameter needs to call the copy constructor, which is marked deleted. The good thing about it, this code will never compile, and you will spot the problem straight away.
First of all I don't really think that Objective-C properties are compatible with non-copyable C++ classes and decided to give my own answer to the question linked, which you can review here.