std ::对象的向量和const-correctness

问题描述 投票:14回答:9

考虑以下:

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;
}

显然,复制构造函数是不够的。我错过了什么?

编辑:Ofc。我无法在operator =()方法中更改this-> c,因此我没有看到如何使用operator =()(尽管std :: vector需要)。

c++ vector const-correctness
9个回答
17
投票

我不确定为什么没有人说,但正确的答案是放弃const,或将A*存储在向量中(使用适当的智能指针)。

您可以通过“复制”调用UB或不执行任何操作(因此不是副本)来为您的类提供可怕的语义,但为什么所有这些都会在UB和坏代码中跳舞?制作那张const你得到了什么? (提示:没什么。)你的问题是概念性的:如果一个类有一个const成员,那么这个类就是const。从根本上说,不能分配const的对象。

只需使它成为非const私有,并且不可变地暴露其价值。对于用户来说,这是等效的,不变的。它允许隐式生成的函数正常工作。


15
投票

STL容器元素必须是可复制构造和assignable1(您的类A不是)。你需要重载operator =

1:§23.1The type of objects stored in these components must meet the requirements of CopyConstructible types (20.1.3), and the additional requirements of Assignabletypes


编辑:

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

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

编辑2

我认为上面的代码片段调用了Undefined Behavior,因为试图抛弃const限定变量的常量会调用UB


7
投票

你错过了一个the big three的赋值运算符(或复制赋值运算符)。


2
投票

存储的类型必须满足CopyConstructible和Assignable要求,这意味着也需要operator =。


1
投票

可能是assignment operator。编译器通常会为您生成一个默认值,但由于您的类具有非平凡的复制语义,因此该功能被禁用。


0
投票

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

C ++ 03

$ 12.8 / 12 - “隐式声明了一个隐式声明的复制赋值运算符,当它的类类型的对象被赋予其类类型的值或从其类类型派生的类类型的值时。如果该类的程序不正确隐式定义了复制赋值运算符的有:

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

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

- 具有无法访问的复制赋值运算符的类类型(或其数组)的非静态数据成员,或

- 具有无法访问的复制赋值运算符的基类。


0
投票

没有const_cast的解决方法。

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

0
投票

我最近遇到了相同的情况,我使用了std :: set,因为它添加元素(insert)的机制不需要=运算符(使用<运算符),这与vector的机制(push_back)不同。

如果性能有问题,您可以尝试unordered_set或其他类似的东西。


0
投票

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

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;
    }

};

特殊的const_cast模板采用指针类型并将其强制转换为可写形式,适用于此类情况。

应该注意的是,const_cast并不总是安全使用,请参阅here

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.