将unique_ptr从set移动到set

时间:2016-10-21 23:12:50

标签: c++ c++11 stl

我似乎无法弄清楚这一点,并尝试了以下建议:

Move `unique_ptr`s between sets

how to move an std::unique_ptr<> from one STL container to another?

我有两组包含唯一指针:

std::set<std::unique_ptr<some_type>> s1, s2;

指针当然是唯一的,但some_type的值可能是也可能不是,所以在将s2连接到s1之后,s1的大小可以与| s1 + s2 |相同或大。

似乎我应该能够做到这一点:

move(s2.begin(), s2.end(), inserter(s1, s1.end()));

但这与clang ++ 3.8 / g ++ 5.4失败了。

这里缺少什么?

3 个答案:

答案 0 :(得分:3)

它不起作用,因为std::set仅允许const访问其元素。没有办法从std::set移出一些东西。见Is it possible to move an item out of a std::set?

在C ++ 14中没有很好的方法可以做到这一点,但在C ++ 17中,为此提供了一个merge方法,它只是重新排列数据结构的内部指针而无需复制或移动任何元素:

s1.merge(s2);

C ++ 14中一个稍微合理的解决方法是将std::set<std::unique_ptr<T>>更改为std::map<T*, std::unique_ptr<T>>。然后你可以这样做:

while (!s1.empty()) {
    s2[s1.begin()->first] = std::move(s1.begin()->second);
    s1.erase(s1.begin());
}

答案 1 :(得分:2)

目前,您将集合成员资格与所有权混为一谈,这就是问题的根源。

解决方案:使用多组原始指针,并将所有权移至其他位置。

重新设想的

const Example = Parse.Object.extend('example_table');

const Table1 = Parse.Object.extend('table1');
const table1Ptr = new Table1().set('objectId', '1');

const Table2 = Parse.Object.extend('table2');
const table2Ptr = new Table2().set('objectId', '6');

const addNewExample = function addNewExample(table1Ptr, table2Ptr) {
  // return the promise that results from the save
  return new Example() // just chaining everything to be terse...
    .set('table1_id', table1Ptr)
    .set('table2_id', table2Ptr)
    .save(null, { useMasterKey: true }) // may not be necessary, depending
    //
    // don't use these old style handlers, use promise syntax
    // which I substitute for the following below.
    // success: function () {
    //    console.log('New object created');
    // },
    // error: function (error) {
    //    console.log('Failed to create new object');
    // }
    .then(
      // fancy fat arrow notation for functions like the cool kids...
      o => console.log('new object: ' + o.id + ' created'),  
      e => console.error('uh oh: ' + e.message)
    );
};

addNewExample(table1Ptr, table2Ptr);

在标准库中move(s2.begin(), s2.end(), inserter(s1, s1.end())); 只是一个美化的演员,它不是一个动作例程。命令式名称形式具有误导性。将move视为std::move

答案 2 :(得分:1)

在C ++ 17中,您可以使用std::set::merge执行您想要的操作,如下例所示:

std::set<std::unique_ptr<T>> s1, s2;
...
s1.merge(s2);

Live Demo

C ++ 11的解决方法相当昂贵,而且有点背叛unique_ptr的概念,这也需要你的对象是可复制的。将要复制您要在第一组中插入的新std::set中的第二个std::unique_ptr的对象:

std::set<std::unique_ptr<T>> s1, s2;
...
for(auto &&e : s2) {
  s1.insert(std::make_unique<T>(*e));
}
s2.clear();

请注意,最后你需要clear你的第二套才能从std::unique_ptr概念的狂野分离引起的视频群聊中恢复过来。

Live Demo