如果从不通过它们修改对实际 const 对象的引用,是否允许 const-casting 掉其常量性?
我有一个抽象类,它声明了常量和非常量成员函数.为了便于讨论,我们假设它看起来像这样:
I have an abstract class that declares const and non-const member functions. For the sake of discussion let's say it looks like this:
class record_interface
{
public:
virtual ~record_interface() = default;
virtual void set_foo(BoundedFloat) = 0;
virtual BoundedFloat get_foo() const = 0;
};
这用作记录的高级表示,当保存到光盘并通过线路传输时,该记录具有不同的表示.因此,大多数实现只需要将其成员转换为所需的高级表示.
This is used as a high-level representation of a record that has different representations when saved to disc and transferred via the wire. So most implementations just need to convert their members to the required high-level representation.
作为有效实现的示例,让我们定义 stored_record
.这用于以有损格式存储高级记录:
As an example of a valid implementation let's define stored_record
. This is used to store the high-level record in a lossy format:
struct stored_record
{
int16_t foo;
};
stored_record
可以实现 record_interface
是有道理的,但由于各种原因它不能(例如,它需要是 trivially_copyable
).我们可以制作一个包装器来实现它的接口:
It makes sense that stored_record
can implement record_interface
but for various reasons it can't (eg. it needs to be trivially_copyable
). We can make a wrapper that implements the interface for it:
class record_wrapper : public record_interface
{
public:
record_wrapper(stored_record & wrapped)
: wrapped_(wrapped) {}
void set_foo(BoundedFloat value) final { wrapped_.foo = convert_to_int16(value); }
BoundedFloat get_foo() const final { return convert_from_int16(wrapped_.foo); }
private:
stored_record & wrapped_;
};
现在的问题是,当给定 const stored_record &
时,我们不能使用包装器,因为包装器存储一个可变引用.我们也不能让它存储非常量引用,因为它无法实现非常量 setter 函数.
Now the problem is that we can't use the wrapper when given a const stored_record &
since
the wrapper stores a mutable reference. We also can't make it store a non-const reference as it won't be able to implement the non-const setter function.
现在我想知道提供一个 const_cast
远离的工厂函数是否有效一个 const stored_record &
的 const
但也返回一个 const 包装器
以便引用实际上不能被修改:
Now I was wondering if it would be valid to provide a factory function that const_cast
s away
a const stored_record &
's const
but also returns a const wrapper
so that the reference cannot actually be modified:
record_wrapper make_wrapper(stored_record & wrapped) {return {wrapped}; }
record_wrapper const make_wrapper(stored_record const & wrapped) { return {const_cast<stored_record &>(wrapped)}; }
EDIT:返回一个 const
record_wrapper
不会真正将返回值限制为 const
,一个解决方案可以是返回一个 const_wrapper
或类似的东西.
EDIT: returning a const
record_wrapper
will not really restrict the returned value to be const
, a solution can be to return a const_wrapper<record_wrapper>
or something similar.
这是 const_cast
的有效用法还是由于 const_cast
去掉了对一个引用的 const
-ness 而导致的未定义行为实际上是 const 对象 - 即使它从未被修改过.
Is this a valid usage of const_cast
or is it undefined behaviour due to const_cast
ing away the const
-ness of a reference to an actually const object - even though it is never modified through it.
推荐答案
Per https://en.cppreference.com/w/cpp/language/const_cast:
const_cast
可以形成一个引用或指向实际引用 const 对象 或指向实际引用 易失性对象.通过非常量访问路径修改常量对象并通过非易失性引用易失性对象 glvalue 导致未定义的行为.
const_cast
makes it possible to form a reference or pointer to non-const type that is actually referring to a const object or a reference or pointer to non-volatile type that is actually referring to a volatile object. Modifying a const object through a non-const access path and referring to a volatile object through a non-volatile glvalue results in undefined behavior.
因此,const_cast
本身是允许的(并且定义良好),即使通过生成的非常量引用实际修改对象是未定义的行为.
So, the const_cast
itself is allowed (and well-defined), even though it would be undefined behavior to actually modify the object via the resulting non-const reference.
相关文章