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
- Hello World C++ - Complete tutorial
- C API - C language bindings
- QoS Policies - QoS configuration