假设我们有某种subscriber
对象利用RAII在破坏时清理自己。
我们有记录的代码声明如下:
1。如果您捕获了返回类型,只要您捕获的值存在,订阅者就会生效。
2. 如果您没有捕获返回类型,则只要您调用其方法创建订阅者的对象,订阅者就会生存。
为了澄清,代码如下所示:
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());
}
}
文档是:
/// 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.
我们能否保证根据是否捕获了返回类型来转移所有权?
答案 0 :(得分:1)
我对你使用的术语有点挣扎,但是如果我得到了正确的问题,我认为,这意味着你的代码示例启发了以下快速而肮脏的mce。
如果你没有为connect_subscriber的返回值提供存储,std :: move将不会成功,id将保留在subscriber_ids_中,否则它将被移动到你的存储中,从而从subscriber_ids_中删除,而不是由任何管理机制适用于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();
}
输出是:
0:31 1:42
0:31 1:42 2:43
0:31 1:42 2:43 3:
输出:
0:31 1:42
0:31 1:42 2:43
0:31 1:42 2:43 3:44
答案 1 :(得分:0)
我不确定你的目标是如何完成#2,但你可以通过返回一个带有转换的代理对象(最好是从rvalue引用)到调用者应该存储的类型(“capture”意味着别的东西)来区分。
该转换可以执行任意操作,例如从自动生命周期列表中删除对象。
允许编译器在返回序列(例如RVO,NRVO)期间忽略复制构造函数调用。但它无法避免转换。