错误:没有匹配的成员函数来调用"push_back"
Error: no matching member function for call to 'push_back'
为什么我在最后两行出现错误?目标是在集合中找到对象,并修改其内容。
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 <
将条目相互比较来确定的。这意味着存在一个容器不变性,如果一个项目a
在std::set
中b
的另一个项目之前,则遵循该!(b < a)
。我这样说是因为这也适用于std::multiset
.由于在一个集合中不允许重复,因此实际上,如果a
在b
之前,则a < b
.如果违反此不变性,则任何需要对集合进行排序的集合操作(例如find
或insert
(都将具有意外(准确地说,未定义(行为。
因此,std::set
将不允许您使用iterator
更改项目,因为您可能会在不知不觉中更改项目的成员,从而影响其在集合中的正确位置,从而破坏不变性,从而导致未定义的行为。
不幸的是,编译器不够聪明,无法理解您的比较函数仅计算某些成员,在这种情况下,仅计算id
。如果编译器和语言能够分析和表达这一点,他们可能会认为,虽然i->id
应该是对const
的引用,但i->m
对于任何其他成员来说,m
可以安全地引用非const
。
您的问题至少有四种可能的解决方案:
最- 简单但最丑陋的解决方案是将需要修改的成员标记为
mutable
.请注意,您必须自己确保更改它们不会影响排序顺序。 - 另一个相当丑陋的解决方案是故意使用
const_cast
,就像const_cast<mystruct &>(*i)
中i
是一个迭代器一样。同样,切勿以这种方式更改对排序顺序有影响的成员。 - 但是,具有额外运行时开销的更优雅的解决方案是向要修改的属性添加指针间接级别(例如,使用
std::unique_ptr
(。但是请注意,如果你在比较函数中使用pointee,你仍然会有破坏集合不变量的风险,只是现在编译器和库将不再阻止你这样做! - 即使要更改影响排序顺序的成员,唯一可行的方法是创建项目的副本,修改副本,擦除旧项目,然后重新插入副本。这允许容器在必要时将副本插入到其他位置。
结语:
- 像
std::unordered_set
这样的哈希容器将具有完全相同的问题,只是在这种情况下,您必须考虑的不是比较函数,而是哈希函数和相等函数。 - 出于给定的原因,
std::map
或std::unordered_map
可能更适合您的问题域,因为在这种情况下,库知道mapped_type
不用于确定容器结构。另请注意,std::map
或std::unordered_map
的value_type
是如何std::pair<const key_type, mapped_type>
而不是std::pair<key_type, mapped_type>
的,原因与更改密钥可能会破坏容器不变量的原因完全相同。
- 什么时候调用组成单元对象的析构函数
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 函数调用中参数的顺序重要吗
- OpenGL - 在抛出"__gnu_cxx::recursive_init_error"实例后终止调用?
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 在c++类上调用void函数
- 为什么 std::unique 不调用 std::sort?
- 调用专用模板时出错"no matching function for call to [...]"
- 选择要调用的构造函数
- C++为什么尽管我调用了void函数,它却不起作用
- 构造函数正在调用一个使用当前类类型的函数
- 变量没有改变?通过向量的函数调用
- 没有为自己的结构调用列表推回方法
- 调用'begin(int [n])'没有匹配函数
- 什么时候调用析构函数
- 如何用参数值调用函数(仅在运行时已知)
- std::cout.imbue()多重调用
- 函数何时会在c++中包含stack_Unwind_Resume调用