Disadvantages of Objective-C++?
Disadvantages of Objective-C++?
我正在用objective - c++为iOS编写一个大型项目。我主要使用Objective-C进行UI和其他Apple api,使用c++进行内部音频处理和其他信息处理。我想知道自由混合Objective-C和c++的缺点。
当然,混合两个对象模型有其固有的局限性和潜在的混乱和混淆。我更好奇的是使用objective - c++将如何影响编译过程,我可能遇到的语法陷阱,可读性问题以及如何避免这些问题,等等。我很想听听你使用objective - c++的经历,以及你对实现这一目标有什么建议。
objc++是非常强大的——你可以为你的问题选择和混合你需要的特性,并同时与C、ObjC和c++交互。我已经用了很多年了。当然,有一些注意事项,最好了解它们,这样您就可以最大限度地减少可能遇到的问题:
当你开始创建重要的程序时,编译时间比ObjC或c++要高得多。
在ObjC类型中声明c++类型有几种常见的方法:
<<ul>我将对这一点略去,因为从OP中可以推断出您熟悉这两种语言。同时,这也是比较公开的关于objc++入门主题的文章之一。
给定c++类型:
class t_thing { public: int a; };
你有很多方法来声明你的变量:
不透明类型:
@interface MONClass : NSObject { void* thing; } @end
应该避免。消除类型安全是不好的。这两个forward选项将引入类型安全。
此变体与ObjC翻译兼容。
前置声明:
class t_thing;
@interface MONClass : NSObject { t_thing* thing; } @end
这比不透明类型好,但智能指针更好——如果你习惯编写现代c++,这是很明显的。
只要你的c++类型在全局命名空间中,这个变体就与ObjC翻译兼容。
使用智能指针的正向声明:
class t_thing;
@interface MONClass : NSObject { t_smart_pointer<t_thing> thing; } @end
如果你打算设置翻译防火墙(例如使用PIMPL和转发来减少依赖),这个是最好的。同样,ObjC对象已经经历了锁定和分配,所以分配一个c++类型也不错。如果您有几个声明,您可能更愿意为您的实现创建一个包装器类型,以减少单个分配。
此变体与ObjC翻译不兼容。
这是提醒你objc++中有一个编译器选项应该启用的好时机:GCC_OBJC_CALL_CXX_CDTORS
。设置此标志后会发生什么?编译器生成隐藏对象方法,这些方法调用c++变量的构造函数和析构函数。如果你使用GCC_OBJC_CALL_CXX_CDTORS
,你的c++变量必须是默认可构造的。如果你不启用这个标志,你必须手动构造和销毁你的ivars-如果你构造它两次或不重写子类的初始化式,那么你将面临UB。
由价值:
#include "thing.hpp"
@interface MONClass : NSObject { t_thing thing; } @end
最高的依赖。这是我选择的路线,对此我有些遗憾。我只是把事情转移到使用更多的c++,并使用智能指针的组合(如上所述)来减少依赖。
此变体与ObjC翻译不兼容。
关于现代ObjC编译器的另一件事:编译器在二进制文件中列出c++类型的ivars/结构。信不信由你,这会消耗大量二进制空间。
这里的要点是程序可以采取多种形式。您可以混合使用这些技术来减少依赖,这是引入依赖防火墙的最佳地点之一,因为ObjC是非常动态的(它的方法必须在一次转换中导出),对象创建需要分配,锁定,引入引用计数系统-单个对象的初始化时间已经相对较高,并且实现将始终是隐藏的。
如果你的大部分程序仍然是在ObjC中,你想保持这种方式,那么你将需要诉诸于在全局命名空间中声明的类型的转发,或者通过对象工厂提供专门化的不透明基类型。就我个人而言,我只是使用了太多的c++,这不是一个理想的选择,并且在全局类型中包装实现很快变得令人厌烦。
同时,由于编译时间很高,反过来也是正确的:如果您可以将实现的重要部分保留为c++,那么您将节省大量编译时间。由于这个原因和ARC(下文),你可以通过尽可能地将原始Apple类型保留为CF类型而获得很多好处,这样你就可以继续构建没有ObjC扩展的c++程序。
语法
我很少有问题但是我对我的c++类保持相当严格:
- 我默认禁止复制和分配。
- 我很少为c++类型声明自定义操作符。
如果你擅长c++,那么你可以避免这个问题,但我更喜欢编译器捕捉我犯的愚蠢的错误。
一个明显的问题是ObjC消息发送中的c++作用域解析。这需要一个空格:
[obj setValue:::func(a)]; // << bad
[obj setValue: ::func(a)]; // << good
我遇到的一个问题是,我从来没有找到一个支持objc++语法的代码格式化器。
ObjC消息
ObjC消息传递和按值返回:当按值返回c++类型时,需要在消息传递
nil
之前进行检查。如果您消息的对象是nil
,那么在现代运行时(x86_64和iOS)上,结果将是内存归零。如果你使用了这个实例,它就是未定义的行为。ObjC消息传递和引用返回:当通过引用返回c++类型时,您需要在消息传递
nil
之前检查。如果你消息的对象是nil
,那么结果将是未定义的行为(引用0/NULL
)。
为了克服ObjC消息传递问题,我通常使用这样的表单:
- (bool)selector:(std::string&)outValue;
返回值为false表示内部错误,返回值为true表示成功。
,你可以安全地写:
if (![obj selector:outString]) { /* bail here */ }
杂集
ARC兼容性:objc++不适合ARC。主要原因是ARC没有遵循混合对象模型。例如:如果你试图将ObjC成员放入c++类型中,编译器将拒绝ARC下的程序。这不是一个真正的问题,因为MRC在objc++中非常简单(假设你也使用SBRM),但它可能是你的程序生命周期的一个问题。
合成属性:你必须为c++类型定义你的属性。
外部工具:除了Xcode的工具集,很少有程序可以很好地处理或识别objc++。文本编辑器,ide,实用程序。
苹果的工具:在Xcode的实用程序中,Xcode对objc++的支持有点低。重构(不可用),导航(使用clang解析器改进),概述(相当原始),objc++可以破坏IB的实用程序,通常不支持项目升级。
- Usages of std::move
- 使用 [] 运算符时"binding reference of type discards qualifiers"
- 如何处理 c++ 中类实现中的"invalid use of non-static data member"?
- 如何将数组从Objective-C发送到C++函数
- 具有变量Number of Arguments的std::函数的矢量
- Capacity of a deque
- Deprecation of _writeBarrier()
- constexpr begin of a std::array
- 如何调整 std::vector of Eigen::MatrixXd 的大小
- C++ "error: invalid use of void expression"
- 我看到"use of undeclared identifier"错误,有人可以告诉我如何解决它吗?
- 赛通"Cannot take address of memoryview slice"
- C++ Version Of Double.longBitsToDouble
- 收到错误"invalid use of non-static data member 'stu::n' "
- C++ Usage of AsyncCallback
- 错误:"Left of getValue must have class/struct/union"
- Centos7 g++ "to_string is not in a member of std"
- 在C++中使用 Catch 测试框架编译错误"error: expected ';' at end of declaration list"
- 传递 std::vector of std::shared_ptr,而不是更新对象
- Disadvantages of Objective-C++?