Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:NVIDIA DALI C API V2 Ref Counting

From Leeroopedia


Knowledge Sources
Domains Data_Pipeline, C_API
Last Updated 2026-02-08 16:00 GMT

Overview

The reference counting header provides an intrusive reference counting base class and a smart pointer template for managing the lifetime of DALI C API v2 objects.

Description

This header file defines the core memory management primitives used by all DALI C API v2 data objects. It belongs to the dali::c_api namespace and provides two primary types: RefCountedObject (the base class) and RefCountedPtr<T> (the smart pointer).

RefCountedObject is a base class that provides thread-safe intrusive reference counting through an std::atomic<int> member initialized to 1. The IncRef() method uses memory_order_relaxed for the atomic increment (sufficient since incrementing only requires visibility, not ordering). The DecRef() method uses memory_order_acq_rel to ensure that all prior modifications are visible before the potential deletion, and automatically deletes the object when the count reaches zero via delete this. The virtual destructor enables correct polymorphic cleanup.

RefCountedPtr<T> is a smart pointer that manages RefCountedObject-derived objects. It supports: construction from a raw pointer (optionally incrementing the ref count for shared ownership), copy construction (increments ref), move construction (transfers ownership without ref changes), copy assignment (with self-assignment safety), move assignment, reset() (decrements and nullifies), and release() (transfers ownership to the caller without decrementing). It also provides converting constructors and assignments for derived-to-base conversions when U* is convertible to T*.

The RefCountedPtr is designed for use in the C API where objects cross the C/C++ boundary: when a handle is passed out to C code, release() transfers ownership; when C code calls DecRef to destroy the object, the ref count drops to zero and the destructor runs.

Usage

Use RefCountedObject as a base class for any C API v2 object that needs reference-counted lifetime management (e.g., ITensor, ITensorList). Use RefCountedPtr<T> within C++ code to safely manage these objects. When passing objects out through the C API, use release() to hand off ownership; when receiving them back, construct a RefCountedPtr with inc_ref=true to share ownership.

Code Reference

Source Location

Signature

namespace dali::c_api {

class RefCountedObject {
 public:
  int IncRef() noexcept;     // Returns new ref count
  int DecRef() noexcept;     // Returns new ref count; deletes this when 0
  int RefCount() const noexcept;
  virtual ~RefCountedObject() = default;
 private:
  std::atomic<int> ref_{1};
};

template <typename T>
class RefCountedPtr {
 public:
  constexpr RefCountedPtr() noexcept = default;
  explicit RefCountedPtr(T *ptr, bool inc_ref = false) noexcept;
  ~RefCountedPtr();

  // Copy/move constructors and assignments (with derived-to-base conversion)
  RefCountedPtr(const RefCountedPtr<T> &other) noexcept;
  template <typename U> RefCountedPtr(const RefCountedPtr<U> &other) noexcept;
  template <typename U> RefCountedPtr(RefCountedPtr<U> &&other) noexcept;

  void reset() noexcept;
  [[nodiscard]] T *release() noexcept;
  constexpr T *operator->() const & noexcept;
  constexpr T &operator*() const & noexcept;
  constexpr T *get() const & noexcept;
  explicit constexpr operator bool() const noexcept;

 private:
  T *ptr_ = nullptr;
};

}  // namespace dali::c_api

Import

#include "dali/c_api_2/ref_counting.h"

I/O Contract

Inputs

Name Type Required Description
ptr T * Yes (constructor) Pointer to a RefCountedObject-derived object
inc_ref bool No If true, increments ref count on construction (default: false, takes ownership)

Outputs

Name Type Description
int (from IncRef) int New reference count after increment
int (from DecRef) int New reference count after decrement (object deleted if 0)
int (from RefCount) int Current reference count
T * (from release) pointer Raw pointer with ownership transferred to caller

Usage Examples

Basic Reference Counting

#include "dali/c_api_2/ref_counting.h"

using namespace dali::c_api;

class MyObject : public RefCountedObject {
 public:
  int value = 42;
};

// Create with initial ref count of 1
RefCountedPtr<MyObject> ptr(new MyObject());
assert(ptr->RefCount() == 1);

// Copy increases ref count
RefCountedPtr<MyObject> ptr2 = ptr;
assert(ptr->RefCount() == 2);

// Reset decreases ref count
ptr.reset();
assert(ptr2->RefCount() == 1);

// When ptr2 goes out of scope, ref count drops to 0 and object is deleted

Passing Objects Through the C API Boundary

// C++ side: create and hand off to C
RefCountedPtr<ITensor> tensor = ITensor::Create(placement);
daliTensor_h handle = tensor.release();  // ref count stays at 1, ownership to C

// C side: use the handle
daliTensorResize(handle, 3, shape, DALI_FLOAT32, "HWC");

// C side: done with the handle
int ref;
daliTensorDecRef(handle, &ref);  // ref == 0, object is destroyed

// C++ side: share ownership with C
RefCountedPtr<ITensorList> tl = ...;
daliTensorList_h tl_handle = tl.release();  // C now owns it
// tl is now null, C code is responsible for calling daliTensorListDecRef

Derived-to-Base Conversion

// TensorWrapper<CPUBackend> derives from ITensor
RefCountedPtr<TensorWrapper<CPUBackend>> specific = Wrap(shared_tensor);

// Implicit conversion to base type
RefCountedPtr<ITensor> generic = std::move(specific);
// specific is now null, generic holds the pointer with same ref count

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment