C++:STL使用const类成员时遇到麻烦

use*_*947 14 c++

这是一个开放式的问题.有效的C++.第3项.尽可能使用const.真?

I would like to make anything which doesn't change during the objects lifetime const. But const comes with it own troubles. If a class has any const member, the compiler generated assignment operator is disabled. Without an assignment operator a class won't work with STL. If you want to provide your own assignment operator, const_cast is required. That means more hustle and more room for error. How often you use const class members?

编辑:作为一项规则,我努力保持const的正确性,因为我做了很多多线程.我很少需要为我的类实现复制控制,从不编写删除代码(除非绝对必要).我觉得const的当前状态与我的编码风格相矛盾.Const迫使我实现赋值运算符,即使我不需要它.即使没有const_cast分配也很麻烦.您需要确保所有const成员比较相等,然后手动复制所有非const成员.

码.希望它能澄清我的意思.您在下面看到的课程不适用于STL.您需要为它实现一个赋值,即使您不需要它.

class Multiply {
public:
    Multiply(double coef) : coef_(coef) {}
    double operator()(double x) const {
        return coef_*x;
    }
private:
    const double coef_;
};
Run Code Online (Sandbox Code Playgroud)

AnT*_*AnT 18

你自己说过你使const"在物体生命期间不会改变的任何东西".然而,您抱怨隐式声明的赋值运算符被禁用.但隐式声明的赋值运算符确实改变了有问题的成员的内容!完全合乎逻辑(根据您自己的逻辑),它正在被禁用.要么是,要么你不应该声明成员const.

此外,为您提供自己的赋值运算符不需要const_cast.为什么?您是否尝试在赋值运算符中指定您声明为const的成员?如果是这样,为什么你声明它为const呢?

换句话说,提供您正在遇到的问题的更有意义的描述.到目前为止你提供的那个以最明显的方式是自相矛盾的.

  • +1:成员是const,还是不是?如果你可以通过为它分配另一个类的实例来改变它,那么它不是const. (4认同)
  • @ rn141:解决方法是修复容器,而不是改变`const`的含义.在C++ 0x中,容器不需要可分配对象. (4认同)
  • 这不是正确性或效率.就个人而言,我发现const的当前行为非直观且过于严苛.除非整个类是const,否则应该允许赋值.至少它比我目前的状况更能让我感到满意. (3认同)

小智 5

我很少使用它们 - 麻烦太大了.当然,在成员函数,参数或返回类型方面,我总是力求const正确性.


Jer*_*fin 5

正如AndreyT指出的那样,在这些情况下,分配(大多数)并没有多大意义.问题是vector(例如)是该规则的一个例外.

从逻辑上讲,您将一个对象复制到该对象中vector,稍后您将获得原始对象的另一个副本.从纯粹的逻辑观点来看,不涉及任务.问题是vector要求对象无论如何都是可分配的(实际上,所有C++容器都可以).它基本上是一个实现细节(在代码中的某个地方,它可能分配对象而不是复制它们)的一部分接口.

对此没有简单的治疗方法.即使定义自己的赋值运算符和使用const_cast也无法真正解决问题.const_cast当您获得const指向您知道实际上未定义的对象的指针或引用时,使用它是完全安全的const.但是,在这种情况下,变量本身定义为const- 试图抛弃constness并赋予它给出未定义的行为.实际上,它几乎总是可以工作(只要它不是static const在编译时已知的初始化器),但是不能保证它.

C++ 11和更新版本为这种情况添加了一些新的曲折.特别是,不再需要将对象分配以存储在向量(或其他集合)中.它们可以移动就足够了.这在这种特殊情况下没有帮助(移动一个const对象比分配它更容易),但在其他一些情况下确实使生活变得更加容易(例如,肯定有可移动但不可分配/可复制的类型) .

在这种情况下,您可以通过添加间接级别使用移动而不是副本.如果你创建一个"外部"和一个"内部"对象,const内部对象中的成员和外部对象只包含指向内部的指针:

struct outer { 
    struct inner {
        const double coeff;
    };

    inner *i;
};
Run Code Online (Sandbox Code Playgroud)

...然后当我们创建一个实例时outer,我们定义一个inner对象来保存const数据.当我们需要做一个赋值时,我们做一个典型的移动赋值:将指针从旧对象复制到新对象,并且(可能)将旧对象中的指针设置为nullptr,所以当它被销毁时,它会赢得'试着破坏内部物体.

如果你想要足够严重,你可以在旧版本的C++中使用(类似)相同的技术.您仍然使用外部/内部类,但每个赋值将分配一个全新的内部对象,或者您使用类似shared_ptr的东西让外部实例共享对单个内部对象的访问权限,并在最后一个外部物体被摧毁

它没有任何真正的区别,但至少在管理矢量使用的分配,你只需要两个引用的inner,而vector被调整本身(调整大小就是一个载体,需要分配与启动).