C++ 将图元移出关联容器
为了好玩,我实现了最简单的排序算法:C++ 将图元移出关联容器,c++,sorting,c++11,move-semantics,multiset,C++,Sorting,C++11,Move Semantics,Multiset,为了好玩,我实现了最简单的排序算法: template<typename Iterator> void treesort(Iterator begin, Iterator end) { typedef typename std::iterator_traits<Iterator>::value_type element_type; // copy data into the tree std::multiset<element_type&g
template<typename Iterator>
void treesort(Iterator begin, Iterator end)
{
typedef typename std::iterator_traits<Iterator>::value_type element_type;
// copy data into the tree
std::multiset<element_type> tree(begin, end);
// copy data out of the tree
std::copy(tree.begin(), tree.end(), begin);
}
但这并没有显著影响性能,即使我正在排序std::string
s
然后我记得关联容器从外部来看是恒定的,也就是说,
std::move
和std::copy
在这里也会做同样的事情:(是否有其他方法将数据移出树?std::set
和std::multiset
仅提供对其元素的const
访问。这意味着您无法将某些内容移出集合。如果您可以移出(或修改它们),请,您可以通过更改项的排序顺序来打破集合。因此C++11禁止这样做
因此,尝试使用
std::move
算法只会调用复制构造函数。我相信您可以为multiset
使用自定义分配器(第三个模板参数)它实际上会将其destroy
方法中的元素移回用户的容器。然后删除集合中的每个元素,在其销毁过程中,它会将字符串移回原始容器。我认为自定义分配器需要有两个阶段的构造(将begin迭代器传递给treesort
函数作为成员保存,但不能在构造期间传递,因为它必须是默认可构造的)
显然,这会很奇怪,对于在set/multiset中没有
pop
方法来说,这是一个愚蠢的解决办法。但这应该是可能的。我喜欢Dave的想法,即一个奇怪的分配器,它能记住每个移动构造对象的来源,并在销毁时自动返回,我从未想过要这么做
但这里有一个更接近你最初尝试的答案:
template<typename Iterator>
void treesort_mv(Iterator begin, Iterator end)
{
typedef typename std::iterator_traits<Iterator>::value_type element_type;
// move the elements to tmp storage
std::vector<element_type> tmp(std::make_move_iterator(begin),
std::make_move_iterator(end));
// fill the tree with sorted references
typedef std::reference_wrapper<element_type> element_ref;
std::multiset<element_ref, std::less<element_type>> tree(tmp.begin(), tmp.end());
// move data out of the vector, in sorted order
std::move(tree.begin(), tree.end(), begin);
}
模板
void treesort_mv(迭代器开始、迭代器结束)
{
typedef typename std::迭代器\特征::值\类型元素\类型;
//将元素移动到tmp存储器中
std::vector tmp(std::make_move_迭代器(begin),
std::make_move_迭代器(end));
//用已排序的引用填充树
typedef std::reference_wrapper element_ref;
std::multiset树(tmp.begin(),tmp.end());
//按排序顺序将数据移出向量
std::move(tree.begin(),tree.end(),begin);
}
这将对引用的multiset
进行排序,因此不需要将它们移出树
但是,当移回原始范围时,移动指定不一定对自指定安全,因此我首先将它们移到向量中,以便在将它们重新指定回原始范围时,不会有自指定
在我的测试中,这比您的原始版本稍微快一点。它可能会失去效率,因为它必须分配向量以及所有树节点。这一事实以及我的编译器使用COW字符串,因此移动并不比复制快多少。您能给我们一些关于您正在排序的字符串的更多信息吗?您能不能rhaps发布您的测试代码供我们使用?看起来您正在尝试优化一些您知道可以通过使用
qsort
进行更多优化的内容。这样做的目的是什么?学习移动语义?@svick是的,我的主要问题是:如果不需要,如何将元素移出关联容器我敢肯定,这个一般性的问题超越了我愚蠢的Treesort例子:)我修改了问题的标题并删除了分配器位,谢谢。我怀疑答案是你不能——似乎没有弹出和返回。使该异常安全可能与std::vector
上的异常安全一样棘手。你不能,但Howard Hinnant做了一个扩展(我不认为有官方文件,但我可能错了)它允许你从容器中提取一个节点,然后你可以移动它的值。。。
template<typename Iterator>
void treesort_mv(Iterator begin, Iterator end)
{
typedef typename std::iterator_traits<Iterator>::value_type element_type;
// move the elements to tmp storage
std::vector<element_type> tmp(std::make_move_iterator(begin),
std::make_move_iterator(end));
// fill the tree with sorted references
typedef std::reference_wrapper<element_type> element_ref;
std::multiset<element_ref, std::less<element_type>> tree(tmp.begin(), tmp.end());
// move data out of the vector, in sorted order
std::move(tree.begin(), tree.end(), begin);
}