【发布时间】:2014-10-03 14:32:11
【问题描述】:
我查看了下面的代码类型,虽然我对问题 (*) 有个人答案,但我想请 C++/设计专家的 cmets。
由于某种原因,Data 是一个具有不可修改标识符和可修改值的对象:
class Data
{
const Id m_id ; // <== note that m_id is a const member variable
Value m_value ;
Data(const Id & id, const Value & value) ;
Data(const Data & data) ;
Data & operator = (const Data & data) ;
// etc.
} ;
设计选择变成了语言选择,因为标识符在类级别 (**) 声明为 const,以避免其(意外)修改,即使是从类成员函数内部...
...但是如你所见,有一个复制赋值运算符,实现为:
Data & Data::operator = (const Data & that)
{
if(this != &that)
{
const_cast<Id &>(this->m_id) = that.m_id ;
this->m_value = that->m_value ;
}
return *this ;
}
复制赋值运算符不是 const 限定的这一事实使这段代码安全(用户只能在非 const 对象上合法地调用此方法而不会引发未定义的行为)。
但是在 C++ 中使用 const_cast 修改其他 const 成员变量是一个不错的类设计选择吗?
我想强调以下几点:
- 数据显然是一个值类型(它有一个
operator =成员函数) - 在这种模式中,一些其他函数也可能合法地需要
const_cast(例如,移动构造函数/赋值和/或交换函数),但不是很多。
请注意,这可能是一个代码审查问题,但这不是“日常”代码。这是一个通用的 C++ 类型设计问题,需要平衡语言的需求/能力和模式/习语的代码解释。
还要注意,mutable(在 C++98 中)不是解决问题的方法,因为其目的是使成员变量尽可能地不可修改。当然,mutable(如 Herb Sutter 的 C++11 帖子“你不知道 const 和 mutable”)更不是一个解决方案。
(*) 我可以私下将我对该问题的回答转发给任何提问的人。
(**) 另一种解决方案是将对象设为非 const,并在接口级别将其设为 const(即不提供可以更改它的函数)
【问题讨论】:
-
那个赋值运算符不安全。它确实调用了未定义的行为。对象本身不是 const 没关系,它的成员仍然是。
-
设计原理听起来很疯狂:“为了避免从类成员函数内部对其进行意外修改。”课堂由你掌控!只是不要修改成员。如果您不能相信您的开发人员不会破坏课程,请解雇开发人员。
-
我想知道
const_cast的哪些用法不调用UB?如我所见,它总是用于从对象中删除cv。看来,它的所有用法都调用了 UB。如果是这样,那为什么语言首先要有它。 -
@Nawaz:当您对非 const 对象进行 const 引用时,可以将 const 从引用中丢弃。您只需要确定引用的对象确实是非常量的。
-
@BenjaminLindley:为什么?规范是这样说的吗?
标签: c++ const-cast