Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/133.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 具有常量成员的结构向量?_C++_Constants_C++03 - Fatal编程技术网

C++ 具有常量成员的结构向量?

C++ 具有常量成员的结构向量?,c++,constants,c++03,C++,Constants,C++03,假设我有 #include <string> #include <vector> using namespace std; struct Student { const string name; int grade; Student(const string &name) : name(name) { } }; #包括 #包括 使用名称空间std; 体类型 { 常量字符串名称; 国际等级; 学生(常量字符串和名称):姓名(名称){} }

假设我有

#include <string>
#include <vector>
using namespace std;

struct Student
{
    const string name;
    int grade;
    Student(const string &name) : name(name) { }
};
#包括
#包括
使用名称空间std;
体类型
{
常量字符串名称;
国际等级;
学生(常量字符串和名称):姓名(名称){}
};
那么,我如何保持学生的矢量呢

int main()
{
    vector<Student> v;

    // error C2582: 'operator =' function is unavailable in 'Student'
    v.push_back(Student("john"));
}
intmain()
{
向量v;
//错误C2582:“运算符=”函数在“学生”中不可用
v、 推回(学生(“约翰”);
}

有没有办法做到这一点,或者我必须分配堆上的所有学生,并存储指向每个学生的指针?

简单的答案是:你不能。如果有
const
成员变量,则编译器无法提供默认的复制赋值运算符。但是,
std::vector
提供的许多操作都需要进行赋值,因此需要(公共)复制赋值运算符

你的选择是:

  • 使
    名称
    常量
  • 编写自己的复制赋值运算符,并想出一种方法来处理“复制”一个
    const
    成员

  • 你不能。您的类型违反了标准容器的“可分配”要求

    ISO/IEC 14882:2003 23.1[库容器要求]/3:

    存储在这些组件中的对象类型必须满足
    CopyConstructible
    类型(20.1.3),以及可分配类型的附加要求

    从表64(
    可分配的
    要求):

    在表64中,
    T
    是用于实例化容器的类型,
    T
    T
    的值,
    u
    是(可能
    const
    T
    的值

    表达式:
    t=u
    ;返回类型:
    T
    ;后置条件:
    t
    相当于
    u


    理论上,在所有情况下,
    std::vector
    等价物都可以选择进行销毁和复制构建,但这不是所选择的合同。如果不需要重新分配,那么对
    vector::operator=
    vector::assign
    等操作使用包含类型的赋值运算符可能会更有效。

    向量元素必须是可复制赋值的,而
    Student
    结构不是因为
    const
    成员。只需使用
    string name
    而不是
    const string name

    除非您有特定的要求,否则类中的常量成员很少有用。如果要防止对成员进行更改,请将其设为私有并添加公共getter函数。

    a
    vector
    通常需要移动元素。每次调用
    push_back()
    时,当向量需要增长时,它会重新分配内存以保持自身连续,并将所有现有元素复制到新空间中。另外,如果调用
    insert()
    remove()
    元素,则必须 被转移。要使
    vector
    能够执行所有操作,元素必须是可复制可分配的,这意味着存储在vector中的类型必须定义赋值运算符

    通常,如果定义一个类,编译器将为该类生成赋值运算符。但是,有些情况下编译器无法做到这一点。其中一种情况是类具有常量成员(请注意,指向const的指针是可以的)

    因此,在您的例子中,问题是
    const字符串名
    。它阻止编译器生成
    运算符=()
    ,这反过来又阻止
    向量
    编译,即使您自己实际上没有对其元素使用赋值

    一种解决方案是使
    名称
    非常量。另一种方法是编写自己的
    Student::operator=()
    ,以某种有意义的方式。第三种方法是,正如您所指出的,使用指针向量而不是对象向量。但是你必须处理他们的分配和取消分配


    另外,编译器无法生成
    运算符=
    的另一种情况是,您的类具有引用成员。

    。。。所以它必须是可分配的,即使我从未分配过任何东西?我不知道。@Philipp:事实上,向量在重新分配时没有分配任何内容。它通常只复制或移动构造新范围,然后删除旧范围。嗯。。。为什么
    vector
    执行拷贝分配?它不能用复制构造+销毁来代替
    操作符=
    ?@OliCharlesworth:为什么
    插入
    需要赋值?我认为它需要一个复制构造函数(使用
    allocator::allocate
    ),因为它不是分配给一个有效的对象,而是分配给一个新分配的、未格式化的内存块,对吗?@Mehrdad:因为在伪代码中,它将执行类似于:
    for(int I=size();I>pos;I--){elements[I]=elements[I-1];}
    。这似乎是编译并链接到VC 2010。你能提供更多关于你的环境的信息吗?这是再现编译失败的完整测试用例吗?@DRH:对不起,我在VC 2008上。是的,这就是整个测试用例。虽然对于其他操作,您需要赋值操作符,但我想不出任何可能的原因,为什么
    push_back
    会有这样的要求。。。然后,可能是实现检查
    可分配的
    需求。