错误:没有匹配的成员函数来调用"push_back"

Error: no matching member function for call to 'push_back'

本文关键字:quot 调用 push back 函数 成员 错误      更新时间:2023-10-16

为什么我在最后两行出现错误?目标是在集合中找到对象,并修改其内容。

using namespace std;
struct mystruct {
int id;
vector<int> y;
mystruct(const int id):id(id) {}
bool operator<(const mystruct& x) const { return id < x.id; }
bool operator==(const mystruct& x) const { return id == x.id; }
};
void test() {
std::set<mystruct> sx;
mystruct x(1);
x.y.push_back(1); x.y.push_back(2);
sx.insert(x);
//
set<mystruct>::iterator i = sx.find(1);
const mystruct* x1 = &(*i);
const mystruct x2 = *x1;
cout << &(i->y) << endl;
cout << &(x1->y) << endl;
cout << x2.id << endl;
x2.y.push_back(3);
i->y.push_back(4);
}

似乎迭代器返回了一个常量对象,并且不允许我使用push_back()来修改向量y。我怎样才能克服这个问题?

错误:

test.cpp:27:8: error: no matching member function for call to 'push_back'
x2.y.push_back(z);
~~~~~^~~~~~~~~
/opt/local/libexec/llvm-6.0/include/c++/v1/vector:688:36: note: candidate function not viable: 'this' argument has type 'const vector<int>', but method is not marked const
_LIBCPP_INLINE_VISIBILITY void push_back(const_reference __x);
^
/opt/local/libexec/llvm-6.0/include/c++/v1/vector:691:36: note: candidate function not viable: 'this' argument has type 'const vector<int>', but method is not marked const
_LIBCPP_INLINE_VISIBILITY void push_back(value_type&& __x);
^

由于x2是用const限定符声明的,即const mystruct x2,C++编译器只考虑const限定的成员函数来调用x2及其任何成员。特别是,它正在寻找要调用void push_back (const int& val) const成员函数。显然,没有这样的函数,因为push_back必须修改容器,因此编译器会产生一个错误,解释到底发生了什么:

候选函数不可行:'this'参数的类型为'const vector<int>',但方法未标记为const

在代码中解决此问题的唯一方法是从x2的声明中删除const限定符。

你不能修改x2的原因是它被声明为const,正如@dasblinkenlight所指出的那样。 @songyuanyao的评论对于访问迭代器引用的对象是正确的,但并没有完全回答这个问题,因为它没有说明为什么设置迭代器只允许const访问。

这样做的原因是,如您所知,std::set是一个有序容器,其结构是通过使用(默认情况下(operator <将条目相互比较来确定的。这意味着存在一个容器不变性,如果一个项目astd::setb的另一个项目之前,则遵循该!(b < a)。我这样说是因为这也适用于std::multiset.由于在一个集合中不允许重复,因此实际上,如果ab之前,则a < b.如果违反此不变性,则任何需要对集合进行排序的集合操作(例如findinsert(都将具有意外(准确地说,未定义(行为。

因此,std::set将不允许您使用iterator更改项目,因为您可能会在不知不觉中更改项目的成员,从而影响其在集合中的正确位置,从而破坏不变性,从而导致未定义的行为。

不幸的是,编译器不够聪明,无法理解您的比较函数仅计算某些成员,在这种情况下,仅计算id。如果编译器和语言能够分析和表达这一点,他们可能会认为,虽然i->id应该是对const的引用,但i->m对于任何其他成员来说,m可以安全地引用非const

您的问题至少有四种可能的解决方案:

  1. 简单但最丑陋的解决方案是将需要修改的成员标记为mutable.请注意,您必须自己确保更改它们不会影响排序顺序。
  2. 另一个相当丑陋的解决方案是故意使用const_cast,就像const_cast<mystruct &>(*i)i是一个迭代器一样。同样,切勿以这种方式更改对排序顺序有影响的成员。
  3. 但是,具有额外运行时开销的更优雅的解决方案是向要修改的属性添加指针间接级别(例如,使用std::unique_ptr(。但是请注意,如果你在比较函数中使用pointee,你仍然会有破坏集合不变量的风险,只是现在编译器和库将不再阻止你这样做!
  4. 即使要更改影响排序顺序的成员,唯一可行的方法是创建项目的副本,修改副本,擦除旧项目,然后重新插入副本。这允许容器在必要时将副本插入到其他位置。

结语:

  • std::unordered_set这样的哈希容器将具有完全相同的问题,只是在这种情况下,您必须考虑的不是比较函数,而是哈希函数和相等函数。
  • 出于给定的原因,std::mapstd::unordered_map可能更适合您的问题域,因为在这种情况下,库知道mapped_type不用于确定容器结构。另请注意,std::mapstd::unordered_mapvalue_type是如何std::pair<const key_type, mapped_type>而不是std::pair<key_type, mapped_type>的,原因与更改密钥可能会破坏容器不变量的原因完全相同。