【问题标题】:Inserting objects into vector using lower_bound with compare struct使用带有比较结构的 lower_bound 将对象插入向量
【发布时间】:2019-04-10 11:38:42
【问题描述】:

我有这门课:

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 是错误的。
很抱歉,如果已经有人问过这个问题,但我还没有找到这个问题的答案。

【问题讨论】:

  • 您确定要将string msg 设为const 吗?这意味着它在初始化后无法更改,这就是阻止您插入它的原因。
  • 感谢所有的答案,我现在明白这个问题了。但是,我无法更改class Mail,包括const string msg。我将向量更改为指针向量vector&lt;CMail*&gt;

标签: c++ vector insert constants lower-bound


【解决方案1】:

C++ 中的错误有时很难诊断。我的建议是始终从顶部开始并首先解决该问题。在这种情况下,有a long list of them,但它们实际上都是一样的——无法生成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;
}

查看它在 Coliru 上的实时运行。

脚注

  • 您可以为比较器使用 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()

【讨论】:

    【解决方案2】:

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

    Deleted implicitly-declared copy assignment operator

    T的默认复制赋值运算符定义为已删除,如果以下任何一项为真:

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

    Deleted implicitly-declared move assignment operator

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

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

    【讨论】:

      猜你喜欢
      • 2020-02-29
      • 2021-11-25
      • 1970-01-01
      • 2021-08-09
      • 1970-01-01
      • 2013-03-05
      • 1970-01-01
      • 2015-07-05
      • 1970-01-01
      相关资源
      最近更新 更多