5

我正在学习Objective-C。我有这样一个“学术”问题,是针对对现代 C++(C++11)有深入了解的 Objective-C 专家提出的。

在 C++11 中,我经常使用移动语义(使用对临时对象的引用,我们可以避免不必要的复制):
什么是移动语义?
http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html

这些链接适用于不熟悉移动语义概念的 Objective-C 编码人员,我很感兴趣 Objective-C 是否有类似的东西,或者可能有一些方法可以实现/模拟这个?

4

2 回答 2

3

Objective-C 不像 C 那样具有这些特性,因为 Objective-C 是纯 C 之上的一组特定特性。Objective-C++ 确实具有这些特性,因为它与 C++ 之上的特性相同。

使移动语义在 C++ 中如此重要的原因之一是 C++ 对值语义的高度重视。通常,您不持有指向 C++ 对象的指针,而是按值持有 C++ 对象。如果没有移动语义,这会导致大量不必要的副本。

Objective-C 不仅没有同样强调值语义,而且完全禁止 Objective-C 对象的值语义;您只能动态创建 Objective-C 对象,不能像复制 C 结构那样复制对象,等等。

@interface Foo
@end
@implementation Foo
@end

int main() {
    Foo f;
    Foo *a, *b;
    *a = *b;
}

error: interface type cannot be statically allocated
Foo f;
    ^
    *
error: cannot assign to class object ('Foo' invalid)
*a = *b;
   ^

所以 C++ 的引用和移动的概念都是用 Objective-C 中的 C 方式完成的,带有指针。当然,这意味着 C++ 与 Objective-C 相比与 C 相比具有许多相同的性能优势,因为它具有相同的避免指针的能力。

于 2012-11-06T23:03:44.460 回答
3

Objective-C 是否有类似的东西,或者可能有一些方法可以实现/模拟这个?

没有。这不是一个大问题,一旦你消化了你正在使用 Objective-C 的抽象层。了解对象是引用计数的并且是堆分配。

现在有两种方法可以做到这一点:

a) 使用 Objective-C++——只需将语言特性与您的内容混合并匹配即可。

b) 使用惯用的 Objective-C。这要追溯到很久以前。一旦你接受对象是引用计数的堆分配并且没有办法解决这个问题(使用 clang),那么你就会学会以不同的方式处理程序。当然,对所有内容进行引用计数并将其放入堆中是有成本的,但在某些情况下您可以利用这些特征。最显着的用途是使用不可变对象和浅拷贝。复制std::stringas 对象将导致 SSO 复制或堆分配。复制一个NSString可以简单地返回自身(在增加或不增加引用计数之后,取决于它是字符串的类型,它可能还需要在该点创建一个具体的副本)。同样,这些对象都只是指针,因此您无需积极关心如何传递对象(值/引用/常量引用/移动)。ObjC 中存在一个更简单的模型,可以利用它。所以这里的设计发生了转变:ObjC 中的“价值优势”减少了,而“支持不变性和共享”更多。

在某些情况下,您可以编写一个 move 方法。由于通用框架类不支持这一点,因此使用对象组合通常更有意义。

由于对象是在堆上分配的,因此移动并不那么重要。精心设计的类考虑了成本以最小化巨大/昂贵的副本,并在内部使用了一些有趣的优化。该成语只是建议您应该采用不同的方法来创建您的类——它们如何共享数据?什么是可变的?什么必须复制?有时,您可能正在处理大的、可变/昂贵的数据并且移动会很方便,但您通常可以将其放在共享容器对象中或重新考虑对象初始化的语义,以最大限度地减少物理复制(并避免奇怪的对象接口中的语义)。除此之外,我不认为移动在纯 Objective-C 中非常有用。当然,它们对于被设计为利用移动语义并能够在多个内存位置创建对象的 C++ 库变得很重要。如果您确实移动了,您通常希望保持该细节的私密性或使其非常明显(例如,我在渲染管道中完成了该操作,以最大程度地减少每个过滤器的大分配)。

您认为有益的示例也将有助于理解您的问题/理由。

于 2012-11-06T22:53:35.467 回答