Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/147.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 将图元移出关联容器_C++_Sorting_C++11_Move Semantics_Multiset - Fatal编程技术网

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);
}