Vector of structs with const members?

2020-03-11 06:03发布

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?

标签: c++ const c++03
4条回答
Emotional °昔
2楼-- · 2020-03-11 06:48

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 of Assignable types.

From table 64 (Assignable requirements):

In Table 64, T is the type used to instantiate the container, t is a value of T, and u is a value of (possibly const) T.

expression: t = u; return type: T; post-condition: t is equivalent to u

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.

查看更多
够拽才男人
3楼-- · 2020-03-11 06:50

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楼-- · 2020-03-11 06:50

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.

查看更多
孤傲高冷的网名
5楼-- · 2020-03-11 06:51

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:

  1. Make name non-const.
  2. Write your own copy-assignment operator, and think of a way to deal with "copying" a const member.
查看更多
登录 后发表回答