Assume we have some kind of subscriber
object that is utilizing RAII to clean itself up on destruction.
We have code that is documented to claim the following:
1. If you capture the return type, the subscriber will live as long as the value you captured lives.
2. If you don't capture the return type, the subscriber will live as long as the object whose method you called to create the subscriber.
To clarify, the code looks like this:
template <class... Args>
id &&connect_subscriber(Args &&... args)
{
auto id = connect_subscriber_with_id(std::forward<Args>(args)...);
{
std::lock_guard<std::mutex> lock(subscriber_id_mutex_);
subscriber_ids_.push_back(std::move(id));
return std::move(subscriber_ids_.back());
}
}
And the documentation is:
/// If the resulting `subscriber_id` is assigned storage at the call
/// site, then the subscription will be managed exclusively by the caller.
/// This means that until the identifier is either destroyed or
/// `disconnect_subscriber()` is called with it, the subscription will stay
/// active.
///
/// Conversely, if the `subscriber_id` is not assigned storage at
/// the call site, it will be managed internally inside the task and the
/// subscription will persist for the life-time of the task.
Can we guarantee that ownership will be transferred based on whether the return type is captured?
I struggle a little bit with the terminology used by you, but if I got the questioin right, I think, what is meant is something along the following quick and dirty mce inspired by your code example.
If you do not provide storage for the return value of connect_subscriber the std::move will not succeed and the id will remain in subscriber_ids_, else it will be moved to your storage and thus removed from subscriber_ids_ and not be managed by whatever mechanism works with subscriber_ids_.
#include <vector>
#include <iostream>
using id = std::string;
std::vector<std::string> subscriber_ids_ = {"31"};
int ids = 42;
id&& connect_subscriber()
{
auto id = std::to_string(ids++);
{
subscriber_ids_.push_back(std::move(id));
return std::move(subscriber_ids_.back());
}
}
void print() {
int i=0;
for(const auto& n:subscriber_ids_)
std::cout << i++ << ":" << n << " ";
std::cout << "\n";
}
int main()
{
connect_subscriber(); // memory not privided
print();
connect_subscriber(); // memory not privided
print();
auto take_it = connect_subscriber(); // memory privided
print();
}
Output is:
0:31 1:42
0:31 1:42 2:43
0:31 1:42 2:43 3:
Output is not:
0:31 1:42
0:31 1:42 2:43
0:31 1:42 2:43 3:44