如果从未通过它们进行修改,是否允许对实际 const 对象的引用进行 const 转换?
我有一个声明 const 和非常量成员函数的抽象类.为了便于讨论,假设它看起来像这样:
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 &
时,我们不能使用包装器,因为包装器存储一个可变引用.我们也不能让它存储一个非常量引用,因为它无法实现非常量设置器函数.
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 wrapper
以便实际无法修改引用:
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 对象――即使它从未被它修改过.
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.
推荐答案
根据 https://en.cppreference.com/w/cpp/language/const_cast:
const_cast
可以形成一个指向非 const 类型的引用或指针,它实际上是在引用 const object 或指向非易失类型的引用或指针,实际上是在引用 易失性对象.通过非 const 访问路径修改 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.
相关文章