让我说我有
#include <string>
#include <vector>
using namespace std;
struct Student
{
const string name;
int grade;
Student(const string &name) : name(name) { }
};
Run Code Online (Sandbox Code Playgroud)
那么,我如何保留学生的矢量?
int main()
{
vector<Student> v;
// error C2582: 'operator =' function is unavailable in 'Student'
v.push_back(Student("john"));
}
Run Code Online (Sandbox Code Playgroud)
有没有办法做到这一点,或者我必须在堆上分配所有学生,并存储指向他们每个人的指针?
简单的答案是:你做不到.如果您有const成员变量,则编译器无法提供默认的复制赋值运算符.但是,许多提供的操作std::vector需要进行分配,因此需要(公共)拷贝分配操作符.
你的选择是:
name非const.const成员的方法.你不能.您的类型违反了标准容器的"可分配"要求.
ISO/IEC 14882:2003 23.1 [lib.container.requirements]/3:
存储在这些组件中的对象类型必须满足
CopyConstructible类型(20.1.3)的要求以及Assignable类型的附加要求.
从表64(Assignable要求):
在表64中,
T是用于实例化容器的类型,t是值的值T,并且u是(可能const)的值T.表达:
t = u; 返回类型:T; 后置条件:t相当于u
理论上,std::vector等价物可以选择在所有情况下进行破坏和复制建筑,但这不是已经选择的合同.如果不需要重新分配,那么使用包含类型的赋值运算符来表示类似的事情,vector::operator=并且vector::assign可能效率更高.
Avector经常需要移动元素。每次调用向量时需要增长时,push_back()它都会重新分配内存以保持自身连续,并将所有现有元素复制到新空间中。此外,如果您调用insert()或remove()元素必须移动。为了vector能够完成所有这些元素必须是可复制赋值的,这意味着您存储在向量中的类型必须定义了赋值运算符。
通常,如果您定义一个类,编译器会为您生成该类的赋值运算符。但是,有些情况下编译器无法做到这一点。其中一种情况是类具有常量成员时(请注意,指向常量的指针是可以的)。
所以,在你的情况下,问题是const string name. 它阻止编译器生成operator=(),从而阻止vector编译,即使您自己实际上并未对其元素使用赋值。
一种解决方案是制作name非常量。另一种是自己写Student::operator=(),以某种有意义的方式。第三种方法是,正如您所指出的,使用指针向量而不是对象向量。但是你必须处理它们的分配和取消分配。
PS 编译器无法生成的另一种情况operator=是您的类具有引用的成员。