【问题标题】:Assignment operations in sort() functionssort() 函数中的赋值操作
【发布时间】:2014-10-21 00:17:39
【问题描述】:
#include <algorithm>
#include <iostream>
#include <list>
#include <vector>

class Int
{
public:
    Int(int i = 0) : m_i(i) { }

public:
    bool operator<(const Int& a) const { return this->m_i < a.m_i; }

    Int& operator=(const Int &a)
    {
        this->m_i = a.m_i;
        ++m_assignments;
        return *this;
    }

    static int get_assignments() { return m_assignments; }

private:
    int m_i;
    static int m_assignments;
};

int Int::m_assignments = 0;

int main()
{
    std::list<Int> l({ Int(3), Int(1) });
    l.sort();
    std::cout << (Int::get_assignments() > 0 ? 1 : 0);

    std::vector<Int> v({ Int(2), Int() });
    std::sort(v.begin(), v.end());
    std::cout << (Int::get_assignments() > 0 ? 2 : 0) << std::endl;

    return 0;
}

上面的代码打印出02,这意味着std::list::sort()不对列表的元素执行任何赋值操作(operator=()),而std::sort()确实对@987654326的元素执行至少1个赋值操作@。

差异源于什么?容器类?排序实现? Int 类的实现?

【问题讨论】:

  • list::sort 不允许使迭代器/对元素的引用无效,因此它不能复制/移动它们。作为一个双向链表,它通过修改指向前一个/下一个元素的指针来执行排序。

标签: c++ c++11 stl assignment-operator


【解决方案1】:

std::list 是一个双向链表,这意味着只需修改列表中的 指针 即可对其进行排序。不需要元素分配。

一个简单的例子是这样的:

头 --> 2 --> 1 --> 空

可以排序为:

______________ | | | v 头 -' 2 空 | | '-------------'

不复制任何元素。

事实上,根据C++11 23.3.5.5 list operations /29,保持迭代器和引用有效的要求意味着,为了提高效率,它真的不能移动东西:

效果:根据operator&lt; 或Compare 函数对象对列表进行排序。 不影响迭代器和引用的有效性。


另一方面,std::vector 将其项目保存在一个连续的数组中,因此没有可操作的指针。如果要对其进行排序,则必须移动项目。

【讨论】:

  • vector的元素不能用移动赋值运算符什么的来移动吗?
  • 他们可以,是的。如果移动分配被标记为 noexcept,它们可能会是(来自std::swap)。取决于排序实现。
猜你喜欢
  • 2023-04-02
  • 1970-01-01
  • 2011-10-18
  • 1970-01-01
  • 2011-07-07
  • 2020-04-16
  • 1970-01-01
  • 1970-01-01
  • 2011-09-03
相关资源
最近更新 更多