在使用g ++ -std = c ++ 0x进行编译时,我有一些编译问题将类型T的元素推回向量。
这是一个最小的例子:
#include <vector>
using namespace std;
class A {
public:
A() { }
A& operator=(A &orig) {
return *this;
}
};
int main(int argc, char **argv) {
A a;
vector<A> b;
A c = a; // This is fine
b.push_back(a); // This is not, but only when compiling with -std=c++0x!
return 0;
}
使用g ++ -Wall -pedantic编译它很好,但是在使用g ++编译时会出现此错误-Wall -pedantic -std = c ++ 0x:
In file included from /usr/include/c++/4.4/vector:69,
from min.cpp:1:
/usr/include/c++/4.4/bits/vector.tcc: In member function ‘void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, _Args&& ...) [with _Args = const A&, _Tp = A, _Alloc = std::allocator<A>]’:
/usr/include/c++/4.4/bits/stl_vector.h:741: instantiated from ‘void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = A, _Alloc = std::allocator<A>]’
min.cpp:20: instantiated from here
/usr/include/c++/4.4/bits/vector.tcc:314: error: no match for ‘operator=’ in ‘__position.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [with _Iterator = A*, _Container = std::vector<A, std::allocator<A> >]() = ((const A&)((const A*)std::forward [with _Tp = const A&](((const A&)((const A*)__args#0)))))’
min.cpp:11: note: candidates are: A& A::operator=(A&)
In file included from /usr/include/c++/4.4/vector:61,
from min.cpp:1:
/usr/include/c++/4.4/bits/stl_algobase.h: In static member function ‘static _BI2 std::__copy_move_backward<true, false, std::random_access_iterator_tag>::__copy_move_b(_BI1, _BI1, _BI2) [with _BI1 = A*, _BI2 = A*]’:
/usr/include/c++/4.4/bits/stl_algobase.h:595: instantiated from ‘_BI2 std::__copy_move_backward_a(_BI1, _BI1, _BI2) [with bool _IsMove = true, _BI1 = A*, _BI2 = A*]’
/usr/include/c++/4.4/bits/stl_algobase.h:605: instantiated from ‘_BI2 std::__copy_move_backward_a2(_BI1, _BI1, _BI2) [with bool _IsMove = true, _BI1 = A*, _BI2 = A*]’
/usr/include/c++/4.4/bits/stl_algobase.h:676: instantiated from ‘_BI2 std::move_backward(_BI1, _BI1, _BI2) [with _BI1 = A*, _BI2 = A*]’
/usr/include/c++/4.4/bits/vector.tcc:308: instantiated from ‘void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, _Args&& ...) [with _Args = const A&, _Tp = A, _Alloc = std::allocator<A>]’
/usr/include/c++/4.4/bits/stl_vector.h:741: instantiated from ‘void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = A, _Alloc = std::allocator<A>]’
min.cpp:20: instantiated from here
/usr/include/c++/4.4/bits/stl_algobase.h:561: error: no match for ‘operator=’ in ‘* -- __result = std::move [with _Tp = A&](((A&)(-- __last)))’
min.cpp:11: note: candidates are: A& A::operator=(A&)
所以似乎找不到合适的算子= A.为什么?当我通过A时,为什么会说with _Iterator = A*
?
答案 0 :(得分:15)
标准容器元素上的语言标准所强加的可分配要求要求t = u
表达式有效,即使u
是const对象也是如此。这个要求是从C ++ 98(见23.1 / 4)
您违反了该要求,因为您的赋值运算符不接受const对象。这立即意味着您的类A
不能用作容器元素类型。
为什么它在C ++ 03中起作用相当无关紧要。它偶然起作用。从错误消息中可以明显看出,库的C ++ 0x实现使用了一些C ++ 0x特定的功能(如std::move
),这就是上述要求发挥作用的原因。但无论如何,C ++ 03实现(甚至C ++ 98实现)也可能无法为您的A
编译。
A c = a;
的示例无关紧要,因为它根本不使用赋值运算符(为什么会在这里?)。
为了修复错误,您应该通过const引用或值接受参数。
答案 1 :(得分:3)
我很确定这是一个安全功能。具有可能改变右侧的复制赋值运算符(或复制构造函数)的类型不在标准容器中使用是安全的 - 例如(现已弃用){{1如果存储在容器中,它将会破坏。
旧的C ++ 03库实现允许这样的不安全代码,但显然他们在C ++ 0x版本中实现了编译时检查 - 可能与移动启用容器一起。
答案 2 :(得分:1)
标准的复制赋值运算符的定义是([class.copy]
}部分:
用户声明的 copy 赋值运算符
X::operator=
是类X
的非静态非模板成员函数,其中只有一个X
类型的参数,X&
,const X&
,volatile X&
或const volatile X&
。
但假设可以从r值RHS进行赋值,X&
和volatile X&
变体可能与容器不兼容。
注意:按值传递,例如X::operator=(X)
是复制和交换习惯用语的基本部分。