Cleaning up DDS Entities in the Modern C++ API

How do I tear down DDS entities in the modern C++ API?

The Modern C++ API for RTI DDS uses shared pointer to implement “reference types,” which include all subclasses of dds::core::Entity, such as DomainParticipant or DataReader, and other classes, such as FlowController, QosProvider. For more information about how different types are implemented, here are the conventions we follow in the API. Shared pointers contain a pointer and a reference count. The associated memory object gets destroyed when the reference count falls to 0. In contrast “value types” get destroyed when they go out of scope. For more information about shared pointers, you can read this article. Thus if any child entity reference exists, the parent entity cannot be deleted since the child will hold a reference to the parent entity. For example, a DomainParticipant won’t be destructed if a Publisher was created using it and a reference to the publisher still exists.

You may have lost track of references to entities you created which might prevent their destruction. In shared pointer parlance this means that the reference count for that entity will not fall to 0. This Knowledge Base (KB) article talks about that.

Can I manually trigger clean up by calling Entity::close()?

Yes, you can do that. Calling close does guarantee that all the memory allocation and threads will be released (this is the method the destructor calls as well). However,this method is not thread-safe - you are responsible to ensure that other threads don’t use the Entity when it’s closed.

Closing an entity will also invalidate any other references to it. Thus you should be very careful when calling close(). We recommend that, whenever possible, you rely on reference counting and a well-defined scope for your entities so they are automatically destroyed and let the destructor perform the cleanup. There are few cases where calling  close() may be needed

  1. When you set a listener when creating an Entity in its constructor. Here is an example.

  2. You call  retain() as explained in conventions.

How do I get a list of created DDS entities?

There are several find functions to look up entities. Some are standard (in the dds namespace), and some are extensions (in the  rti namespace).

In particular, to return all the entities, use:

find_<entitytype>() e.g. rti::sub::find_datareaders()

Note that Topics, DataReaders and DataWriters are template classes. For these template classes, there are corresponding type-erased classes that allow returning multiple instances with different templates.

AnyDataReader and AnyDataWriter

So here is an example of how you would list out all the DataReaders you created in a subscriber:

std::vector<dds::sub::AnyDataReader> drs;
dds::sub::find_datareaders(sub, std::back_inserter(drs));

// Access the 3rd element if it is of type Foo
if (drs[2].type_name() == "Foo") {
    DataReader<Foo> foo_dr = drs[2].get<Foo>();
    LoanedSamples<Foo> samples = foo_dr.take();
    // ...
}

More examples like this are in the programming how-to’s.

Can I declare a DDS entity as a pointer?

No, you shouldn't, since internally all DDS entity objects are implemented as shared pointers. For more details refer this KB article.