问题
Let's say I have
#include <string>
#include <vector>
using namespace std;
struct Student
{
const string name;
int grade;
Student(const string &name) : name(name) { }
};
How do I, then, keep a vector of students?
int main()
{
vector<Student> v;
// error C2582: 'operator =' function is unavailable in 'Student'
v.push_back(Student("john"));
}
Is there even a way to do this, or must I allocate all the students on the heap, and store a pointer to each of them instead?
回答1:
You can't. Your type violates the "Assignable" requirement for standard containers.
ISO/IEC 14882:2003 23.1 [lib.container.requirements] / 3:
The type of objects stored in these components must meet the requirements of
CopyConstructible
types (20.1.3), and the additional requirements ofAssignable
types.
From table 64 (Assignable
requirements):
In Table 64,
T
is the type used to instantiate the container,t
is a value ofT
, andu
is a value of (possiblyconst
)T
.expression:
t = u
; return type:T
; post-condition:t
is equivalent tou
In theory, a std::vector
equivalent could choose to do destruction and copy construction in all cases, but that's not the contract that has been chosen. If reallocation isn't required, then using the contained type's assignment operator for things like vector::operator=
and vector::assign
might be significantly more efficient.
回答2:
The simple answer is: you can't. If you have const
member variables, then the compiler can't supply a default copy-assignment operator. However, many of the operations that std::vector
provides need to make assignments, and therefore require a (public) copy-assignment operator.
Your options are:
- Make
name
non-const
. - Write your own copy-assignment operator, and think of a way to deal with "copying" a
const
member.
回答3:
A vector
often needs to move elements around. Every time a vector needs to grow when you call push_back()
it reallocates memory to keep itself contiguous, and copies all the existing elements into the new space. Also if you call insert()
or remove()
elements must
be shifted. For vector
to be able to do all that the elements must be copy-assignable, which means that the type you store in the vector must have the assignment operator defined.
Generally, if you define a class, the compiler will generate the assignment operator for that class for you. However, there are cases when the compiler is unable to do that. One of these cases is when the class has constant members (note that pointers-to-const are ok).
So, in your case, the problem is the const string name
. It prevents the compiler from generating operator=()
, which in turn prevents vector
from compiling, even though you do not actually use assignment on its elements yourself.
One solution is to make name
non-const. The other is to write your own Student::operator=()
, in some way that makes sense. The third way is, as you have pointed out, to use a vector of pointers rather than a vector of objects. But then you have to handle their allocation and de-allocation.
P.S. The other case when the compiler cannot generate operator=
is when your class has members that are references.
回答4:
Elements of vectors must be copy-assignable, which your Student
struct isn't because of the const
member. Simply use string name
instead of const string name
.
Unless you have a specific requirement, constant members in classes are seldom useful. If you want to prevent changes to the member, make it private and add a public getter function.
来源:https://stackoverflow.com/questions/8467968/vector-of-structs-with-const-members