#c #vector #insert #constants #lower-bound
#c #вектор #вставить #константы #нижняя граница
Вопрос:
У меня есть этот класс:
class Mail {
public:
Mail(const string amp; msg) : msg(msg) {}
const string msg;
};
И эта структура, которая сравнивает два почтовых объекта:
struct Compare {
bool operator()(const Mail amp; mail, Mail const amp; mail2) const {
return mail.msg < mail2.msg;
}
};
Я хочу иметь вектор с почтовыми объектами, отсортированными по их сообщению const string msg
. Однако, когда я пытаюсь вставить новый объект в вектор с помощью lower_bound
, я получаю много ошибок, в том числе:
передача ‘const string как ‘this’ аргумент отбрасывает квалификаторы.
int main() {
vector <Mail> mails;
Mail mail2("1");
mails.push_back(mail2);
const string msg = "2";
Mail mail(msg);
auto low = lower_bound(mails.begin(), mails.end(), mail, Compare());
// mails.push_back(mail); // OK
mails.insert(low, mail); // passing ‘const string as ‘this’ argument discards qualifiers
return 0;
}
Я пока не очень разбираюсь const
в использовании и не могу понять, что const
неправильно.
Прошу прощения, если об этом уже спрашивали, но я пока не нашел ответа на эту проблему.
Комментарии:
1. вы уверены, что хотите
string msg
бытьconst
? Это означает, что его нельзя изменить после инициализации, и именно это мешает вам вставить его.2. Спасибо за все ответы, теперь я понимаю проблему. Однако я не могу изменить
class Mail
включениеconst string msg
. Я изменил вектор на вектор указателейvector<CMail*>
.
Ответ №1:
Ошибки в C иногда бывает трудно диагностировать. Мой совет — всегда начинать с самого верха и сначала разрешить его. В этом случае их длинный список, но все они на самом деле об одном и том же — оператор присваивания для Mail
не может быть сгенерирован.
Подумайте об этом так: компилятор полезен и пытается сгенерировать (и внутри lower_bound()
, использовать) эту функцию:
Mailamp; operator=( constamp; Mail mail )
{
msg = mail.msg;
return *this;
}
Но это невозможно, потому что это назначение в теле недопустимо из-за msg
того const
, что . Вы также не можете написать это самостоятельно, поскольку вы также не можете назначить const
переменной.
Обычно вам не нужны переменные-члены const
, потому что они становятся const
, если экземпляр класса сам const
:
const auto mail1 = Mail{"1"};
auto mail2 = Mail{"2"};
mail1.msg = "3"; // FAIL! msg is const since mail1 is const
mail2.msg = "4"; // Ok! msg is not const
Если вам действительно нужен const
член, вы не можете использовать операторы присваивания с классом. Это разрывы.
Удалите это const
, и все работает:
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
class Mail {
public:
Mail(const string amp; msg) : msg(msg) {}
string msg; //////////////////////////////// Not const!
};
struct Compare {
bool operator()(const Mail amp; mail, Mail const amp; mail2) const {
return mail.msg < mail2.msg;
}
};
int main() {
vector <Mail> mails;
Mail mail2("1");
mails.push_back(mail2);
const string msg = "2";
Mail mail(msg);
auto low = lower_bound(mails.begin(), mails.end(), mail, Compare());
// mails.push_back(mail); // OK
mails.insert(low, mail); // OK!
return 0;
}
Посмотрите, как он работает в реальном Coliruвремени.
Сноски:
- Вы могли бы использовать лямбда-выражение для сопоставителя, чтобы избежать некоторых шаблонов вокруг класса
Compare
:
const auto low = lower_bound( begin(mails), end(mails), mail,
[]( const autoamp; mail1, const autoamp; mail2 )
{ return mail1.msg < mail2.msg; } );
- Вы можете использовать
vector::emplace_back()
для создания элементов на месте, избегая копирования. Следующие блоки выполняют то же самое, но второй более эффективен:
const auto mail = Mail{"2"};
mails.push_back( mail2 ); // Copies
mails.emplace_back("2"); // Creates it right in the vector
- Рассмотрите возможность использования
vector::reserve()
, если вы знаете, сколько элементов вы поместите в свой вектор.
Ответ №2:
Проблемы здесь связаны с удаленным оператором присваивания копирования и удаленным оператором присваивания перемещения из-за const string msg;
члена в Mail
классе:
Удален неявно объявленный оператор присваивания копирования
Оператор присваивания копирования по умолчанию для класса
T
определяется как удаленный, если выполняется любое из следующих действий:
T
имеет нестатический элемент данных неклассового типа (или его массив), которыйconst
;Удален неявно объявленный оператор присваивания перемещения
Неявно объявленный или используемый по умолчанию оператор присваивания перемещения для класса
T
определяется как удаленный, если выполняется любое из следующих действий:
- T имеет нестатический элемент данных, который
const
;