Skip to main content

C++ API Reference

HDDS provides C++ bindings through hdds-cpp, exposing the full DDS API with modern C++17 idioms.

Installation

# From source
git clone https://github.com/example/hdds-cpp.git
cd hdds-cpp && mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)
sudo make install

# CMake integration
find_package(hdds REQUIRED)
target_link_libraries(myapp hdds::hdds)

Core Classes

DomainParticipantFactory

#include <hdds/dds.hpp>

// Get singleton factory
hdds::DomainParticipantFactory& factory =
hdds::DomainParticipantFactory::get_instance();

// Create participant
hdds::DomainParticipant* participant = factory.create_participant(
0, // domain ID
hdds::DomainParticipantQos::default_qos()
);

// Delete participant
factory.delete_participant(participant);

DomainParticipant

class DomainParticipant {
public:
// Topic creation
template<typename T>
Topic<T>* create_topic(
const std::string& name,
const TopicQos& qos = TopicQos::default_qos()
);

// Publisher/Subscriber
Publisher* create_publisher(
const PublisherQos& qos = PublisherQos::default_qos()
);

Subscriber* create_subscriber(
const SubscriberQos& qos = SubscriberQos::default_qos()
);

// Discovery
InstanceHandle get_instance_handle() const;
DomainId get_domain_id() const;

// Lifecycle
ReturnCode enable();
ReturnCode close();
};

Publisher

class Publisher {
public:
template<typename T>
DataWriter<T>* create_datawriter(
Topic<T>* topic,
const DataWriterQos& qos = DataWriterQos::default_qos()
);

ReturnCode delete_datawriter(DataWriterBase* writer);

// QoS
ReturnCode set_qos(const PublisherQos& qos);
PublisherQos get_qos() const;

// Status
StatusMask get_status_changes() const;
};

Subscriber

class Subscriber {
public:
template<typename T>
DataReader<T>* create_datareader(
Topic<T>* topic,
const DataReaderQos& qos = DataReaderQos::default_qos()
);

ReturnCode delete_datareader(DataReaderBase* reader);

// QoS
ReturnCode set_qos(const SubscriberQos& qos);
SubscriberQos get_qos() const;
};

DataWriter

template<typename T>
class DataWriter {
public:
// Write operations
ReturnCode write(const T& data);
ReturnCode write(const T& data, const Timestamp& timestamp);
ReturnCode write_w_handle(const T& data, InstanceHandle handle);

// Instance management
InstanceHandle register_instance(const T& data);
ReturnCode unregister_instance(const T& data, InstanceHandle handle);
ReturnCode dispose(const T& data, InstanceHandle handle);

// Status
LivelinessLostStatus get_liveliness_lost_status();
OfferedDeadlineMissedStatus get_offered_deadline_missed_status();
PublicationMatchedStatus get_publication_matched_status();

// Lifecycle
ReturnCode wait_for_acknowledgments(const Duration& timeout);
};

DataReader

template<typename T>
class DataReader {
public:
// Read operations (keep in cache)
ReturnCode read(
std::vector<T>& data,
std::vector<SampleInfo>& info,
size_t max_samples = LENGTH_UNLIMITED
);

// Take operations (remove from cache)
ReturnCode take(
std::vector<T>& data,
std::vector<SampleInfo>& info,
size_t max_samples = LENGTH_UNLIMITED
);

// Filtered operations
ReturnCode read_w_condition(
std::vector<T>& data,
std::vector<SampleInfo>& info,
ReadCondition* condition
);

// Status
LivelinessChangedStatus get_liveliness_changed_status();
RequestedDeadlineMissedStatus get_requested_deadline_missed_status();
SubscriptionMatchedStatus get_subscription_matched_status();

// Conditions
ReadCondition* create_readcondition(
SampleStateMask sample_states,
ViewStateMask view_states,
InstanceStateMask instance_states
);
};

QoS Classes

DataWriterQos

DataWriterQos qos = DataWriterQos::default_qos();

// Reliability
qos.reliability().kind = ReliabilityKind::RELIABLE;
qos.reliability().max_blocking_time = Duration::from_millis(100);

// History
qos.history().kind = HistoryKind::KEEP_LAST;
qos.history().depth = 10;

// Durability
qos.durability().kind = DurabilityKind::TRANSIENT_LOCAL;

// Deadline
qos.deadline().period = Duration::from_millis(100);

// Liveliness
qos.liveliness().kind = LivelinessKind::MANUAL_BY_TOPIC;
qos.liveliness().lease_duration = Duration::from_secs(1);

DataReaderQos

DataReaderQos qos = DataReaderQos::default_qos();

// Match writer settings
qos.reliability().kind = ReliabilityKind::RELIABLE;
qos.history().kind = HistoryKind::KEEP_LAST;
qos.history().depth = 100;

// Resource limits
qos.resource_limits().max_samples = 10000;
qos.resource_limits().max_instances = 100;
qos.resource_limits().max_samples_per_instance = 100;

Listeners

DataWriterListener

class MyWriterListener : public hdds::DataWriterListener {
public:
void on_offered_deadline_missed(
DataWriter* writer,
const OfferedDeadlineMissedStatus& status) override
{
std::cerr << "Deadline missed: " << status.total_count << "\n";
}

void on_publication_matched(
DataWriter* writer,
const PublicationMatchedStatus& status) override
{
std::cout << "Matched readers: " << status.current_count << "\n";
}
};

// Attach listener
auto listener = std::make_unique<MyWriterListener>();
writer->set_listener(listener.get(), StatusMask::all());

DataReaderListener

class MyReaderListener : public hdds::DataReaderListener {
public:
void on_data_available(DataReader* reader) override {
std::vector<SensorData> data;
std::vector<SampleInfo> info;

auto* typed_reader = static_cast<DataReader<SensorData>*>(reader);
typed_reader->take(data, info);

for (size_t i = 0; i < data.size(); ++i) {
if (info[i].valid_data) {
process(data[i]);
}
}
}

void on_subscription_matched(
DataReader* reader,
const SubscriptionMatchedStatus& status) override
{
std::cout << "Matched writers: " << status.current_count << "\n";
}
};

WaitSet

// Create waitset
hdds::WaitSet waitset;

// Attach conditions
auto status_cond = reader->get_statuscondition();
status_cond->set_enabled_statuses(StatusMask::data_available());
waitset.attach_condition(status_cond);

// Wait for events
std::vector<Condition*> active;
while (running) {
ReturnCode ret = waitset.wait(active, Duration::from_secs(1));

if (ret == ReturnCode::OK) {
for (auto* cond : active) {
if (cond == status_cond) {
std::vector<SensorData> samples;
std::vector<SampleInfo> infos;
reader->take(samples, infos);
// Process samples...
}
}
}
}

Type Support

Generated Types

// From IDL:
// struct SensorData {
// uint32 sensor_id;
// float value;
// uint64 timestamp;
// };

#include "SensorData.hpp"

// Register type
hdds::TypeSupport<SensorData>::register_type(participant, "SensorData");

// Create topic
auto* topic = participant->create_topic<SensorData>("SensorTopic");

Dynamic Types

#include <hdds/dynamic.hpp>

// Build type at runtime
auto type_builder = hdds::DynamicTypeBuilder("SensorData");
type_builder.add_member("sensor_id", hdds::TypeKind::UINT32);
type_builder.add_member("value", hdds::TypeKind::FLOAT32);
type_builder.add_member("timestamp", hdds::TypeKind::UINT64);

auto dynamic_type = type_builder.build();

// Create dynamic data
hdds::DynamicData data(dynamic_type);
data.set_uint32("sensor_id", 1);
data.set_float32("value", 25.5f);
data.set_uint64("timestamp", now_ns());

Error Handling

// ReturnCode enum
enum class ReturnCode {
OK,
ERROR,
UNSUPPORTED,
BAD_PARAMETER,
PRECONDITION_NOT_MET,
OUT_OF_RESOURCES,
NOT_ENABLED,
IMMUTABLE_POLICY,
INCONSISTENT_POLICY,
ALREADY_DELETED,
TIMEOUT,
NO_DATA
};

// Check return codes
if (writer->write(data) != ReturnCode::OK) {
std::cerr << "Write failed\n";
}

// Exception-based API (optional)
#define HDDS_USE_EXCEPTIONS
try {
writer->write_or_throw(data);
} catch (const hdds::Exception& e) {
std::cerr << "Error: " << e.what() << "\n";
}

Memory Management

RAII Wrappers

// Smart pointer wrappers
hdds::unique_participant participant(
factory.create_participant(0, qos));

hdds::unique_publisher publisher(
participant->create_publisher());

hdds::unique_datawriter<SensorData> writer(
publisher->create_datawriter(topic));

// Automatic cleanup on scope exit

Sample Loans

// Zero-copy write
auto loan = writer->loan_sample();
loan->sensor_id = 1;
loan->value = 42.5f;
loan->timestamp = now_ns();
loan.write(); // Returns sample to pool after write

Thread Safety

// All HDDS objects are thread-safe for:
// - Concurrent reads from multiple threads
// - Concurrent writes to different writers
// - Concurrent reads from different readers

// Single writer is NOT thread-safe for concurrent writes
// Use external synchronization or separate writers per thread

std::mutex writer_mutex;
{
std::lock_guard<std::mutex> lock(writer_mutex);
writer->write(data);
}

Complete Example

#include <hdds/dds.hpp>
#include "SensorData.hpp"

int main() {
// Create participant
auto& factory = hdds::DomainParticipantFactory::get_instance();
auto* participant = factory.create_participant(0);

// Register type and create topic
hdds::TypeSupport<SensorData>::register_type(participant);
auto* topic = participant->create_topic<SensorData>("SensorTopic");

// Create publisher and writer
auto* publisher = participant->create_publisher();

DataWriterQos writer_qos;
writer_qos.reliability().kind = ReliabilityKind::RELIABLE;
auto* writer = publisher->create_datawriter(topic, writer_qos);

// Publish data
SensorData sample;
sample.sensor_id = 1;
sample.value = 25.5f;
sample.timestamp = std::chrono::steady_clock::now()
.time_since_epoch().count();

writer->write(sample);

// Cleanup
publisher->delete_datawriter(writer);
participant->delete_publisher(publisher);
participant->delete_topic(topic);
factory.delete_participant(participant);

return 0;
}

Next Steps