使用带有比较结构的lower_bound将对象插入矢量

Inserting objects into vector using lower_bound with compare struct

本文关键字:bound 对象 插入 lower 比较 结构      更新时间:2023-10-16

我有这个类:

class Mail {
public:
Mail(const string & msg) : msg(msg) {}
const string msg;
};

以及这个结构,它比较两个 Mail 对象:

struct Compare {
bool operator()(const Mail & mail, Mail const & mail2) const {
return mail.msg < mail2.msg;
}
};

我想有一个向量,其中包含按消息const string msg排序的邮件对象。但是,当我尝试使用lower_bound将新对象插入矢量时,我收到许多错误,包括:

将"const 字符串"作为"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错了。
很抱歉,如果已经问过这个问题,但我还没有找到这个问题的答案。

C++中的错误有时很难诊断。我的建议是始终从顶部开始,然后首先解决这个问题。在这种情况下,它们的列表很长,但它们实际上都是关于同一件事 - 无法生成Mail赋值运算符。

这样想,编译器很有帮助,并试图生成(并在lower_bound()内部使用)这个函数:

Mail& operator=( const& Mail mail ) 
{ 
msg = mail.msg; 
return *this;
}

但不能,因为身体中的分配由于msgconst而无效。您也不能自己编写它,因为您也无法分配给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 & msg) : msg(msg) {}
string msg; //////////////////////////////// Not const!
};
struct Compare {
bool operator()(const Mail & mail, Mail const & 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;
}

看到它在科利鲁上直播。

脚注

  • 你可以使用lambda作为比较器,以避免类Compare周围的一些样板
const auto low = lower_bound( begin(mails), end(mails), mail, 
[]( const auto& mail1, const auto& 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()

此处的问题与已删除的复制赋值运算符和已删除的移动赋值运算符有关,因为Mail类中的const string msg;成员:

删除了隐式声明的复制赋值运算符

如果满足以下任一条件,则类T的默认复制赋值运算符定义为已删除

  • T有一个非类类型(或其数组)的非静态数据成员,该成员const;

删除了隐式声明的移动赋值运算符

如果满足以下任一条件,则类T的隐式声明或默认移动赋值运算符定义为已删除

  • T 有一个非静态数据成员,该成员const;