STL сортирует вектор по клиентскому оператору «<». Почему я должен определять оператор «<» как const? - PullRequest
0 голосов
/ 08 октября 2019

Я определил класс "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
=====================================

Почему существует так много "конструкции копирования" и "назначения"?

Почему функция подкачки не была вызвана? Как вектор переставляет элементы?

Мне сказали, что когда номер элемента вектора мал, он использует другой алгоритм, но не подкачку.

Конструктор по умолчанию HasPtr ()и конструктор String HasPtr (const std :: string & s = std :: string ()) не является неоднозначным. Я не знаю почему.

Спасибо

Ответы [ 2 ]

2 голосов
/ 08 октября 2019

Оператор сравнения должен только сравнивать, бессмысленно и вредно сравнивать и изменять. Определяя его, const гарантирует, что ничего плохого не произойдет.

вектор должен иметь доступ к операторам копирования. Он также проверит конструктор перемещения и оператор присваивания перемещения, если первый не был доступен.

1 голос
/ 08 октября 2019

О const квалификаторе operator<():

Представьте, что у вас есть эта функция

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
{ /* ... */ }

тогда вызов a<b в предыдущем my_fnct() не будет разрешен компилятором, поскольку параметр a объявлен как const, но operator<() не обещает в своем прототипе, чтоa не будет изменен ..

С другой стороны, если ваш HasPtr::operator<() объявлен как

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

, то вызов a<b в предыдущем my_fnct() будетбудет разрешено компилятором, поскольку ключевое слово const в конце прототипа гарантирует, что левый операнд сравнения (a в моем предыдущем примере) не будет изменен.

...