【问题标题】:Does Objective-C have C++11 rvalue references and move semantics equivalents or how to implement this?Objective-C 是否具有 C++11 右值引用和移动语义等价物或如何实现?
【发布时间】:2012-11-03 13:17:04
【问题描述】:

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

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

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

【问题讨论】:

  • 我不明白“对象语义”与“值语义”是什么。这是你编的吗?如果是这样,请更清楚地说明您的目标。
  • @KerrekSB:提问者没有编造出来,但我认为他所说的“对象语义”是指我称之为“实体语义”的东西。简而言之,具有实体语义的类型具有 object identity 的概念,这对该类型的用户有用/有意义/无论什么,而具有值语义的类型您只希望通过值与 @ 进行比较987654324@。显然,差异可能会变得模糊,这是一个设计目标,而不是类型的严格属性。在 C++ 中,它通常伴随着可复制类型与不可复制类型之间的区别:实体不是常规复制的。
  • 重新标记您的问题。我相信这是 Objective-C 问题,而不是 C++ 问题,C++ 可能是次要标签,并且 [equivalent] 具有误导性。询问 Objective-C 专家,假设他们对 C++11 知之甚少,因此更详细地解释您希望在 Objective-C 中实现的目标。我对 Objective-C 几乎一无所知 - 但也许这有帮助:stackoverflow.com/questions/2002174/copy-mutablecopy
  • @Alexander 如果您描述这些 C++11 特性的方式对于非 C++ 专家来说会有些不明确 - 那么 Objective-C 专家将能够提供帮助。届时您将拥有更广泛的受众,更多的成功机会。最好的办法是描述你想在 Objective-C 中做什么 - 尽可能少地提及 C++...

标签: c++ objective-c c++11 copy-constructor move-semantics


【解决方案1】:

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

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

现在有两种方法可以采取:

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

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

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

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

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

【讨论】:

    【解决方案2】:

    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 相比具有许多相同的性能优势,因为它具有相同的避免指针的能力。

    【讨论】:

      猜你喜欢
      • 2013-02-14
      • 2011-06-26
      • 1970-01-01
      • 2022-12-08
      • 2012-04-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多