STL 按客户 '<' 运算符对向量进行排序。为什么要将“<”运算符定义为常量?

STL sort a vector by customer '<' operator. Why should I define the '<' operator as const?

我定义了一个class"HasPtr":

#include <iostream>
#include <string>

class HasPtr {
public:
   HasPtr()
      : ps(new std::string()), i() {
      std::cout << "Default constructor execute" << std::endl;
   }
   HasPtr(const std::string &s, int a)
      : ps(new std::string(s)), i(a) {
      std::cout << "Sting with int constructor execute" << std::endl;
   }
   HasPtr(const std::string &s = std::string())
      : ps(new std::string(s)), i(std::stoi(s)) {
      std::cout << "String constructor execute" << std::endl;
   }
   HasPtr(const HasPtr &obj)
      : ps(new std::string(*obj.ps)), i(obj.i) {
      std::cout << "Copy constructor execute" << std::endl;
   }
   HasPtr & operator=(const HasPtr &rhs) {
      std::cout << "Assign execute" << std::endl;
      ps = new std::string(*rhs.ps);
      i = rhs.i;
      return *this;
   }
   ~HasPtr() {
      delete ps;
   }

   std::string get_str() const {
      return *ps;
   }

   int get_i() const {
      return i;
   }

   bool operator<(const HasPtr obj) const {
      std::cout << "Operator < execute" << std::endl;
      return i < obj.i;
   }

   friend void swap(HasPtr &lhs, HasPtr &rhs) {
      std::cout << "HasPtr::swap function execute" << std::endl;
      std::swap(lhs.ps, rhs.ps);
      std::swap(lhs.i, rhs.i);
   }

private:
   std::string *ps;
   int i;
};

这是我的 main.cpp:

#include <iostream>
#include <vector>
#include <algorithm>
#include "HasPtr.h"

int main() {
   std::vector<HasPtr> v;
   v.push_back(std::to_string(10));
   v.push_back(std::to_string(5));
   v.push_back(std::to_string(7));
   v.push_back(std::to_string(3));
   v.push_back(std::to_string(2));
   v.push_back(std::to_string(9));

   std::cout << "==========List the elements==========" << std::endl;
   for (const auto &i : v) {
      std::cout << i.get_str() << " ";
   }
   std::cout << std::endl;
   std::cout << "=====================================" << std::endl;

   sort(v.begin(), v.end());

   std::cout << "==========List the elements==========" << std::endl;
   for (const auto &i : v) {
      std::cout << i.get_str() << " ";
   }
   std::cout << std::endl;
   std::cout << "=====================================" << std::endl;
}
  1. 我想知道为什么要将bool operator<(const HasPtr obj) const定义为常量? 我认为向量中的所有元素都不是常量。对吧?
  2. 执行不明白:
String constructor execute
Copy constructor execute
String constructor execute
Copy constructor execute
Copy constructor execute
String constructor execute
Copy constructor execute
Copy constructor execute
Copy constructor execute
String constructor execute
Copy constructor execute
Copy constructor execute
Copy constructor execute
Copy constructor execute
String constructor execute
Copy constructor execute
Copy constructor execute
Copy constructor execute
Copy constructor execute
Copy constructor execute
String constructor execute
Copy constructor execute
==========List the elements==========
10 5 7 3 2 9
=====================================
Copy constructor execute
Copy constructor execute
Operator < execute
Copy constructor execute
Operator < execute
Assign execute
Assign execute
Copy constructor execute
Copy constructor execute
Operator < execute
Copy constructor execute
Operator < execute
Copy constructor execute
Operator < execute
Assign execute
Copy constructor execute
Operator < execute
Assign execute
Copy constructor execute
Copy constructor execute
Operator < execute
Copy constructor execute
Operator < execute
Assign execute
Assign execute
Assign execute
Assign execute
Copy constructor execute
Copy constructor execute
Operator < execute
Copy constructor execute
Operator < execute
Assign execute
Assign execute
Assign execute
Assign execute
Assign execute
Copy constructor execute
Copy constructor execute
Operator < execute
Copy constructor execute
Operator < execute
Copy constructor execute
Operator < execute
Assign execute
Copy constructor execute
Operator < execute
Assign execute
==========List the elements==========
2 3 5 7 9 10
=====================================

为什么有这么多"copy construction"和"assignment"?

  1. 为什么没有调用swap函数?向量如何重新排列元素?

有人告诉我,当向量的元素数较小时,它会使用不同的算法但不会交换。

默认构造函数HasPtr()和String构造函数HasPtr(const std::string &s = std::string()) 没有歧义。不知道为什么。

谢谢

比较运算符应该只是比较,比较和修改是没有意义和有害的。定义它 const 保证不会发生任何不好的事情。

vector 需要复制构造函数复制赋值运算符可用。如果前者不可用,它将检查移动构造函数和移动赋值运算符。

关于 operator<()const 限定词:

假设你有这个功能

int
my_fnct(const HasPtr &a,
        const HasPtr &b)
{
  int result=12;
  // ... do something ...
  if(a<b) // <--- the comparison is important
  {
    result+=100; // or whatever ...
  }
  // ... do something ...
  return result;
}

如果您的 HasPtr::operator<() 被声明为

bool operator<(const HasPtr &obj) // <-- without const here
{ /* ... */ }

那么之前 my_fnct() 中的调用 a<b 将 编译器不允许,因为参数 a 是 声明为 constoperator<() 承诺 在其原型中 a 不会被修改..

另一方面,如果您的 HasPtr::operator<() 声明为

bool operator<(const HasPtr &obj) const // <-- const at the end here
{ /* ... */ }

那么前一个 my_fnct() 中的调用 a<b 将被允许 编译器自原型末尾的 const 关键字 确保比较的左操作数(我之前的 a example)不会被修改。