ObjC setter 在 get 调用时会自动复制作为参数传递的 C++ 对象吗?

问题描述 投票:0回答:2

我最近读到了关于 std::unique_ptr 作为 Objective c 中的 @property 的内容,并且将

unique_ptr
作为属性存储在 ObjC 中的建议如下:

-(void) setPtr:(std::unique_ptr<MyClass>)ptr {
    _ptr = std::move(ptr);
}

我的问题是在 ObjC 中,在这种情况下参数是否被复制?因为如果发生这种情况,

unique_ptr
永远不会被宣布为财产权?

c++ objective-c objective-c++
2个回答
1
投票

我的问题是在 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查看。


0
投票

我不希望代码编译为

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);
}
© www.soinside.com 2019 - 2024. All rights reserved.