C++ std::对象向量和常量正确性

C++ std::对象向量和常量正确性,c++,vector,const-correctness,C++,Vector,Const Correctness,考虑以下几点: class A { public: const int c; // must not be modified! A(int _c) : c(_c) { // Nothing here } A(const A& copy) : c(copy.c) { // Nothing here } }; int main(int argc, char *argv

考虑以下几点:

class A {
public:
    const int c; // must not be modified!

    A(int _c)
    :   c(_c)
    {
        // Nothing here
    }

    A(const A& copy)
    : c(copy.c)
    {
        // Nothing here
    }    
};



int main(int argc, char *argv[])
{
    A foo(1337);

    vector<A> vec;
    vec.push_back(foo); // <-- compile error!
    
    return 0;
}
A类{
公众:

const int c;//不能修改! A(整数c) :c(_c) { //这里什么都没有 } A(施工图A和副本) :c(副本c) { //这里什么都没有 } }; int main(int argc,char*argv[]) { 阿福(1337); 向量向量机;
vec.push_back(foo);//c
operator=()
方法中,因此我不知道如何使用
operator=()
(尽管
std::vector
需要)(或复制赋值操作符),STL容器元素中的一个必须是复制可构造和可赋值的1(您的类
A
不是)。您需要重载
操作符=

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


编辑

免责声明:我不确定以下代码是否100%安全。如果它调用UB或其他东西,请告诉我

A& operator=(const A& assign)
{
    *const_cast<int*> (&c)= assign.c;
    return *this;
}
A&运算符=(常量A&赋值)
{
*const_cast(&c)=assign.c;
归还*这个;
}

编辑2


我认为上面的代码片段调用了未定义的行为,因为试图摆脱
const
限定变量的常量调用
UB

我认为您正在使用的向量函数的STL实现需要一个赋值操作符(请参阅标准中Prason的引用)但是,根据下面的引文,由于代码中的赋值运算符是隐式定义的(因为它不是显式定义的),因此由于您的类还具有常量非静态数据成员,因此您的程序的格式不正确

C++03

$12.8/12-“隐式声明 复制赋值运算符是隐式的 当其类的对象 为类型指定了其类的值 类型或类类型的值 从其类类型派生。一个程序 如果 复制赋值运算符是隐式的 定义有:

-常量类型的非静态数据成员,或

-非静态数据 引用类型的成员,或

-a 类类型的非静态数据成员 (或其阵列)具有 无法访问的复制分配运算符, 或

-具有不可访问属性的基类 复制赋值运算符


您还需要实现一个复制构造函数,如下所示:

class A {
public:
    const int c; // must not be modified!

    A(int _c)
    ...

    A(const A& copy)
    ...  

    A& operator=(const A& rhs)
    {
        int * p_writable_c = const_cast<int *>(&c);
        *p_writable_c = rhs.c;
        return *this;
    }

};
A类{
公众:

const int c;//不能修改! A(整数c) ... A(施工图A和副本) ... A运算符=(常数A和rhs) { int*p_writable_c=const_cast(&c); *p_可写_c=rhs.c; 归还*这个; } };
特殊的
const_cast
模板采用指针类型,并将其转换回可写形式,用于此类情况


需要注意的是,使用
const\u cast
并不总是安全的,请参阅。

const\u cast的解决方法

A& operator=(const A& right) 
{ 
    if (this == &right) return *this; 
    this->~A();
    new (this) A(right);
    return *this; 
} 

我不知道为什么没有人这么说,但正确的答案是删除
常量
,或者将
A*
存储在向量中(使用适当的智能指针)

通过让“copy”调用UB或什么都不做(因此不是一个副本),你可以给你的类带来糟糕的语义,但是为什么要在UB和坏代码周围跳舞呢?通过使
常量
,你得到了什么?(提示:什么都没有。)您的问题是概念性的:如果一个类有一个常量成员,那么该类就是常量。从根本上说,常量对象是无法分配的。


只需将其设置为非常量私有,并不可变地公开其值。对于用户来说,这是等效的,常量方面的。它允许隐式生成的函数正常工作。

我最近遇到了同样的情况,我使用了std::set,因为其添加元素(insert)的机制不需要=运算符(使用<运算符),与vector的机制不同(向后推)


如果性能有问题,您可以尝试无序集或其他类似的方法。

我只想指出,从C++11及更高版本开始,问题中的原始代码编译得很好!完全没有错误。但是,如果使用“placement new”(新位置),则会更好“在内部,因此更有效的方法是,将对象直接复制到向量末尾的内存中,而不是拥有额外的中间副本

(重点加上):

std::vector::emplace\u back

将新元素追加到容器的末尾。元素通过
std::allocator\u traits::construct
构造,它通常使用placement new在容器提供的位置构造元素

下面是一个快速演示,演示了
vec.push_back()
vec.emplace_back()
现在都可以正常工作

在此处运行:


编译错误是什么?不要含糊其辞,做一个;写一个我想你有一个选择:要么你失去了常量,要么你失去了使用向量的能力。如果你开始解决这个问题,并允许
操作符=
修改常量成员,你现在已经给了任何一段代码同样的方法。const int c;//不能被修改!你上面的评论是不是意味着“c”不应该被使用类A的对象或类A本身的成员修改?@anand:c应该只在构造函数中设置。在我的spe中
#include <cstdio>
#include <vector>

class A {
public:
    const int c; // must not be modified!

    A(int _c)
    :   c(_c)
    {
        // Nothing here
    }

    // Copy constructor 
    A(const A& copy)
    : c(copy.c)
    {
        // Nothing here
    }    
};

int main(int argc, char *argv[])
{
    A foo(1337);
    A foo2(999);

    std::vector<A> vec;
    vec.push_back(foo); // works!
    vec.emplace_back(foo2); // also works!
    
    for (size_t i = 0; i < vec.size(); i++)
    {
        printf("vec[%lu].c = %i\n", i, vec[i].c);
    }
    
    return 0;
}
vec[0].c = 1337
vec[1].c = 999