C ++:STL的烦恼与const类成员 [英] C++: STL troubles with const class members

查看:97
本文介绍了C ++:STL的烦恼与const类成员的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个开放式问题。
有效的C ++。 真的吗?



我想做任何在对象生命周期const中不会改变的东西。但是const带来了麻烦。如果一个类有任何const成员,编译器生成的赋值运算符被禁用。没有赋值运算符,类将不能使用STL。如果您想要提供自己的赋值运算符,则需要 const_cast 。这意味着更多的喧嚣和更多的错误的余地。使用const类成员的频率如何?



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



代码。我的意思是。下面你看到的类将不能使用STL。

  class Multiply {
public :
乘法(double coef):coef_(coef){}
double operator()(double x)const {
return coef_ * x;
}
private:
const double coef_;
};正如AndreyT所指出的,在这些情况下,赋值(大多数情况下是这样)。 )没有多大的意义。问题是向量(例如)是该规则的例外。



逻辑上,你将对象复制到向量中,并且稍后您将返回原始对象的另一个副本。从纯逻辑的角度来看,没有涉及任务。问题是向量要求对象是可分配的(实际上,所有C ++容器都是)。它基本上是一个实现细节(它的代码中的某处,它可以分配对象而不是复制它们)的一部分接口。



没有简单的治疗。即使定义自己的赋值运算符并使用 const_cast ,也不能真正解决问题。当你得到一个 const 指针或引用一个你知道实际上没有的对象时,使用 const_cast 定义为 const 。然而,在这种情况下,变量本身定义为 const - 试图丢弃 const ness并赋值给它未定义的行为。实际上,它几乎总是工作(只要它不是 static const 与编译时已知的初始化器),但不能保证。 p>

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



在这种情况下,您可以 通过添加间接级别。如果你创建一个outer和一个inner对象,用内部对象中的 const 成员,外部对象只包含一个内部的指针:

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

inner * i;
};

...然后当我们创建一个 outer ,我们定义一个 inner 对象来保存 const 数据。当我们需要做一个赋值时,我们做一个典型的移动赋值:将指针从旧对象复制到新对象,(可能)将旧对象中的指针设置为一个nullptr,所以当它被销毁时, t尝试销毁内部对象。



如果你想要足够糟糕,你可以使用(排序)相同的技术在旧版本的C + +。你仍然会使用外部/内部类,但每个赋值将分配一个新的内部对象,或者你会使用像shared_ptr这样的外部实例共享访问一个内部对象,并清理它,当最后一个外部对象被破坏。



它没有任何真正的区别,但至少对于在管理一个向量中使用的赋值,你只有两个引用一个 inner ,而向量正在自己调整大小(调整大小是为什么向量需要可分配的开始)。


It is an open ended question. Effective C++. Item 3. Use const whenever possible. Really?

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?

EDIT: As a rule, I strive for const correctness because I do a lot of multithreading. I rarely need to implemented copy control for my classes and never code delete (unless it is absolutely necessary). I feel that the current state of affairs with const contradicts my coding style. Const forces me to implement assignment operator even though I don't need one. Even without const_cast assignment is a hassle. You need to make sure that all const members compare equal and then manually copy all non-const member.

Code. Hope it will clarify what I mean. The class you see below won't work with STL. You need to implement an assignment for it, even though you don't need one.

class Multiply {
public:
    Multiply(double coef) : coef_(coef) {}
    double operator()(double x) const {
        return coef_*x;
    }
private:
    const double coef_;
};

解决方案

As AndreyT pointed out, under these circumstances assignment (mostly) doesn't make a lot of sense. The problem is that vector (for one example) is kind of an exception to that rule.

Logically, you copy an object into the vector, and sometime later you get back another copy of the original object. From a purely logical viewpoint, there's no assignment involved. The problem is that vector requires that the object be assignable anyway (actually, all C++ containers do). It's basically making an implementation detail (that somewhere in its code, it might assign the objects instead of copying them) part of the interface.

There is no simple cure for this. Even defining your own assignment operator and using const_cast doesn't really fix the problem. It's perfectly safe to use const_cast when you get a const pointer or reference to an object that you know isn't actually defined to be const. In this case, however, the variable itself is defined to be const -- attempting to cast away the constness and assign to it gives undefined behavior. In reality, it'll almost always work anyway (as long as it's not static const with an initializer that's known at compile time), but there's no guarantee of it.

C++ 11 and newer add a few new twists to this situation. In particular, objects no longer need to be assignable to be stored in a vector (or other collections). It's sufficient that they be movable. That doesn't help in this particular case (it's no easier to move a const object than it is to assign it) but does make life substantially easier in some other cases (i.e., there are certainly types that are movable but not assignable/copyable).

In this case, you could use a move rather than a copy by adding a level of indirection. If your create an "outer" and an "inner" object, with the const member in the inner object, and the outer object just containing a pointer to the inner:

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

    inner *i;
};

...then when we create an instance of outer, we define an inner object to hold the const data. When we need to do an assignment, we do a typical move assignment: copy the pointer from the old object to the new one, and (probably) set the pointer in the old object to a nullptr, so when it's destroyed, it won't try to destroy the inner object.

If you wanted to badly enough, you could use (sort of) the same technique in older versions of C++. You'd still use the outer/inner classes, but each assignment would allocate a whole new inner object, or you'd use something like a shared_ptr to let the outer instances share access to a single inner object, and clean it up when the last outer object is destroyed.

It doesn't make any real difference, but at least for the assignment used in managing a vector, you'd only have two references to an inner while the vector was resizing itself (resizing is why a vector requires assignable to start with).

这篇关于C ++:STL的烦恼与const类成员的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆