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, the conventions we follow in the API are here for the current release or here for release 5.3.0. 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. Calling  close() is needed when you call  retain() as explained in Conventions (see links above).

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.

Comments

thanks a lot, I was looking a way to clean up DDS entities manually.