如果从不通过它们进行修改,是否允许 const 强制转换对实际 const 对象的引用的常量性?

Lia*_*ros 10 c++ interface constants language-lawyer

我有一个声明常量和非常量成员函数的抽象类。为了讨论起见,让我们说它看起来像这样:

class record_interface
{
public:
   virtual ~record_interface() = default;

   virtual void set_foo(BoundedFloat) = 0;
   virtual BoundedFloat get_foo() const = 0;
};
Run Code Online (Sandbox Code Playgroud)

这用作记录的高级表示,当保存到光盘并通过线路传输时,该记录具有不同的表示。所以大多数实现只需要将它们的成员转换为所需的高级表示。

作为有效实现的示例,让我们定义stored_record. 这用于以有损格式存储高级记录:

struct stored_record
{
    int16_t foo;
};
Run Code Online (Sandbox Code Playgroud)

stored_record可以实现是有道理的,record_interface但由于各种原因它不能(例如,它需要是trivially_copyable)。我们可以制作一个为其实现接口的包装器:

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_;
};
Run Code Online (Sandbox Code Playgroud)

现在的问题是当给定 a 时我们不能使用包装器,const stored_record &因为包装器存储了一个可变引用。我们也不能让它存储非常量引用,因为它无法实现非常量 setter 函数。

现在,我在想,如果这将是有效提供工厂函数const_cast总是aconst stored_record &const还要返回const wrapper,以便参考实际上不能被修改:

record_wrapper make_wrapper(stored_record & wrapped) {return {wrapped}; }
record_wrapper const make_wrapper(stored_record const & wrapped) { return {const_cast<stored_record &>(wrapped)}; }
Run Code Online (Sandbox Code Playgroud)

编辑:返回 aconst record_wrapper不会真正将返回值限制为const,解决方案可以是返回 aconst_wrapper<record_wrapper>或类似的东西。

const_cast是由于const_cast消除了const对实际 const 对象的引用的有效性,还是未定义的行为- 即使它从未通过它进行修改。

rua*_*akh 14

根据https://en.cppreference.com/w/cpp/language/const_cast

const_cast使得可以形成一个指向实际上指向一个const 对象的非 const 类型的引用或指针,或者一个指向实际上指向一个volatile 对象的非 volatile 类型的引用或指针。通过非常量访问路径修改常量对象并通过非易失性泛左值引用易失性对象导致未定义的行为。

因此,它const_cast本身是允许的(并且定义良好),即使通过生成的非常量引用实际修改对象是未定义的行为。