cpp

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

C++

C++

Use this skill for C++ code that needs clear ownership, strong type modeling, maintainable file boundaries, and predictable native integration. When the code is part of a Nitro Module, pair this with
build-nitro-modules
for generated specs, Promise mapping, CMake, and HybridObject constraints.
本技能适用于需要清晰所有权、强类型建模、可维护文件边界以及可预测原生集成的C++代码。当代码属于Nitro Module的一部分时,请结合
build-nitro-modules
使用,以处理生成的规范、Promise映射、CMake和HybridObject约束。

Workflow

工作流

  1. Read the generated headers, public API shape, and local ownership patterns before editing.
  2. Model valid states with types before implementing behavior.
  3. Keep headers small and stable; push implementation details into
    .cpp
    files.
  4. Split helpers by responsibility instead of growing a primary implementation file.
  5. Make ownership, lifetime, threading, and async boundaries explicit.
  1. 编辑前先阅读生成的头文件、公共API形态和本地所有权模式。
  2. 在实现行为之前,先用类型对有效状态建模。
  3. 保持头文件精简且稳定;将实现细节放入
    .cpp
    文件中。
  4. 按职责拆分辅助函数,不要让主实现文件不断膨胀。
  5. 明确所有权、生命周期、线程和异步边界。

Type-Safe API Design

类型安全的API设计

  • Represent state variants with
    std::variant
    , inheritance, or separate concrete types. Do not encode variants as one struct with many
    std::optional
    fields.
  • Keep related values nonoptional on the variant where they are valid. If
    barcode
    and
    barcodeType
    must exist together, put both on
    ScannedBarcode
    .
  • Use
    std::optional
    for real domain absence inside one state, not for "maybe this object is a different kind of thing".
  • Prefer compile-time flow over caller-side optional probing.
  • 使用
    std::variant
    、继承或独立的具体类型来表示状态变体。不要将变体编码为带有多个
    std::optional
    字段的单个结构体。
  • 在变体有效的情况下,将相关值设为非可选。如果
    barcode
    和
    barcodeType
    必须同时存在,则将两者都放在
    ScannedBarcode
    中。
  • std::optional
    用于表示单个状态中真实的业务缺失,而不是用于“这个对象可能是另一种类型”的情况。
  • 优先使用编译期流程,而非调用方的可选值探测。

File Organization

文件组织

  • Treat a filename as a scope contract.
    HybridDataScanner.cpp
    should implement
    HybridDataScanner
    ; it should not also define unrelated geometry conversions, UI helpers, platform adapters, or extension-style utilities.
  • Keep one primary class, struct family, or cohesive algorithm per file by default. Split delegates, adapters, converters, platform shims, and reusable helpers into named files such as
    GeometryConversions.cpp
    ,
    DataScannerDelegate.cpp
    , or
    PlatformViewController.cpp
    .
  • Put private helpers in an anonymous namespace only when they are small and only serve the file's primary type. Move reusable or bulky helpers to a separate file under a
    detail
    namespace or an internal folder.
  • Use line count as a review signal: files below roughly 300 lines are usually fine; files above that need a clear reason tied to one cohesive responsibility. Size caused by unrelated helpers, conversions, or platform glue is a design issue.
  • Do not hide large implementation bodies in headers. Use headers for declarations, templates that must be visible, and small inline functions only.
  • Put conversions on the element type or as a named converter function for one element when the conversion only reads one element. The one-element converter may still return multiple values; compose callers with standard loops,
    std::transform
    , insertion into a set, or
    std::accumulate
    .
  • Add collection-level helpers only when the collection has real domain behavior, such as validation across elements, deduplication, ordering, batching, caching, nonempty checks, or error aggregation.
  • 将文件名视为作用域约定。
    HybridDataScanner.cpp
    应当实现
    HybridDataScanner
    ;不应同时定义不相关的几何转换、UI辅助函数、平台适配器或扩展类工具。
  • 默认情况下,每个文件只包含一个主类、结构体族或内聚的算法。将委托、适配器、转换器、平台兼容层和可复用辅助函数拆分到命名文件中,例如
    GeometryConversions.cpp
    、
    DataScannerDelegate.cpp
    或
    PlatformViewController.cpp
    。
  • 仅当私有辅助函数体量很小且仅服务于文件的主类型时,才将其放在匿名命名空间中。将可复用或体量较大的辅助函数移到
    detail
    命名空间下的独立文件或内部文件夹中。
  • 将行数作为评审信号:大约300行以下的文件通常没问题;超过300行的文件需要有明确的理由,且理由需与单一内聚职责相关。由不相关的辅助函数、转换或平台粘合代码导致的文件过大属于设计问题。
  • 不要将大型实现体隐藏在头文件中。头文件仅用于声明、必须可见的模板和小型内联函数。
  • 当转换仅读取单个元素时,将转换方法放在元素类型上,或作为单个元素的命名转换函数。单元素转换函数仍可返回多个值;调用方通过标准循环、
    std::transform
    、插入集合或
    std::accumulate
    来组合使用。
  • 仅当集合具有真实的业务行为时,才添加集合级辅助函数,例如跨元素验证、去重、排序、批处理、缓存、非空检查或错误聚合。

Ownership and Async

所有权与异步

  • Prefer RAII and explicit ownership with values,
    std::unique_ptr
    , and
    std::shared_ptr
    only when shared lifetime is real.
  • Avoid raw owning pointers. Raw pointers and references should be non-owning and documented by surrounding lifetime.
  • Use
    std::variant
    ,
    std::optional
    , and strong structs to express API flow instead of stringly typed states.
  • Keep quick, deterministic, local work synchronous. Do not introduce executors, promises, or callback plumbing for simple value construction, cached metadata, or pure transforms.
  • Do not block caller threads for I/O, long CPU work, or platform callbacks. Use the project's async abstraction, an owned executor/thread, or Nitro
    Promise<T>
    when the operation can wait.
  • Avoid platform main/UI threads unless the platform API requires them. Keep main-thread blocks small and move parsing, conversion, I/O, session negotiation, and CPU work to an owned executor/thread or async API.
  • Keep thread-affine state behind a clear owner. Do not mix mutexes, queues, callbacks, and shared ownership without a documented boundary.
  • Treat repeated executor, queue, thread, or callback hops as an architecture smell. A component should either own the executor/thread it works on, or cross into that owner once at the public async boundary or native callback boundary.
  • If a workflow bounces between platform, worker, JS/Nitro, and callback threads in multiple nested places, stop and redesign the object/lifecycle/API. Excessive hops hide latency, make ordering harder to reason about, and create future performance problems.
  • Do not fix races or readiness bugs with
    sleep_for
    ,
    usleep
    , timers, extra executor hops, or calling the same method twice. Fix ownership, the state machine, lifecycle event, callback contract, or async boundary instead. Retry only for external nondeterminism such as hardware, OS services, remote services, or network, and keep retries bounded, cancellable, and idempotent.
  • Treat
    std::mutex
    as last-resort synchronization, not default listener or callback plumbing. Before adding one, identify the exact shared mutable values, concurrent callers, and why one owner thread/queue, immutable snapshots, or message passing is not enough.
  • Never hold a mutex while invoking callbacks, crossing into JS/Nitro, calling platform APIs with unknown reentrancy, or calling user-provided code. Copy/snapshot the data needed for dispatch, unlock, then call out.
  • 优先使用RAII和值语义的显式所有权,仅当确实存在共享生命周期时才使用
    std::shared_ptr
    。
  • 避免使用原始拥有指针。原始指针和引用应为非所有性质,并通过周边生命周期说明其有效性。
  • 使用
    std::variant
    、
    std::optional
    和强类型结构体来表达API流程,而非字符串类型的状态。
  • 快速、确定性的本地工作保持同步执行。不要为简单的值构造、缓存元数据或纯转换引入执行器、promise或回调管道。
  • 不要因I/O、长时间CPU运算或平台回调而阻塞调用方线程。当操作需要等待时,使用项目的异步抽象、自有执行器/线程或Nitro
    Promise<T>
    。
  • 避免使用平台主线程/UI线程,除非平台API要求。保持主线程代码块精简,将解析、转换、I/O、会话协商和CPU工作移到自有执行器/线程或异步API中。
  • 将线程亲和状态置于明确的所有者之后。在没有文档化边界的情况下,不要混合使用互斥锁、队列、回调和共享所有权。
  • 将频繁的执行器、队列、线程或回调跳转视为架构坏味道。组件要么拥有其运行的执行器/线程,要么在公共异步边界或原生回调边界处一次性进入该所有者。
  • 如果工作流在平台、工作线程、JS/Nitro和回调线程之间的多个嵌套位置来回跳转,请停下来重新设计对象/生命周期/API。过多的跳转隐藏了延迟,使得顺序更难推理,并会带来未来的性能问题。
  • 不要用
    sleep_for
    、
    usleep
    、定时器、额外的执行器跳转或重复调用同一方法来修复竞态或就绪问题。相反,应修复所有权、状态机、生命周期事件、回调约定或异步边界。仅针对硬件、操作系统服务、远程服务或网络等外部非确定性情况进行重试,且重试需有边界、可取消且具备幂等性。
  • 将
    std::mutex
    视为最后的同步手段,而非默认的监听器或回调管道。在添加互斥锁之前,先明确具体的共享可变值、并发调用方,以及为什么单所有者线程/队列、不可变快照或消息传递不足以解决问题。
  • 绝对不要在持有互斥锁的情况下调用回调、进入JS/Nitro、调用具有未知重入性的平台API或调用用户提供的代码。复制/快照调度所需的数据,解锁后再进行外部调用。

Nitro Notes

Nitro注意事项

  • C++ HybridObjects must inherit from the generated
    Hybrid*Spec
    class and copy generated signatures exactly.
  • Use
    std::shared_ptr<Promise<T>>
    for generated async methods.
  • Keep generated-spec implementation files focused on the HybridObject. Put conversion helpers, OpenCV utilities, platform adapters, and CMake-only glue in separate files.
  • Pair JS-facing base HybridObjects with native interfaces or adapter classes when C++ needs to work with Swift/Kotlin-backed platform services.
  • C++ HybridObject必须继承自生成的
    Hybrid*Spec
    类,并严格复制生成的签名。
  • 生成的异步方法使用
    std::shared_ptr<Promise<T>>
    。
  • 生成规范的实现文件应专注于HybridObject。将转换辅助函数、OpenCV工具、平台适配器和仅用于CMake的粘合代码放在单独的文件中。
  • 当C++需要与Swift/Kotlin实现的平台服务协作时,将面向JS的基础HybridObject与原生接口或适配器类配对使用。