通常,const_cast<>()
在 C++ 代码中使用它通常被认为是一种不好的做法,因为它(大多数时候)揭示了设计中的缺陷。
虽然我完全同意这一点,但我想知道使用const_cast<>()
的是什么情况是可以的,并且是唯一的解决方案。
你们能给我一些你知道/遇到的例子吗?
非常感谢你。
通常,const_cast<>()
在 C++ 代码中使用它通常被认为是一种不好的做法,因为它(大多数时候)揭示了设计中的缺陷。
虽然我完全同意这一点,但我想知道使用const_cast<>()
的是什么情况是可以的,并且是唯一的解决方案。
你们能给我一些你知道/遇到的例子吗?
非常感谢你。
它几乎被设计为仅与不正确的旧 API 一起使用,即与您无法更改的具有非 const 接口但实际上不会改变接口上的任何内容的函数一起使用
就像其他人所说的那样,它的主要目的是const
从对象中删除,以便传递给您知道不会修改参数的非常量正确函数。
有一个技巧(Meyers?)来避免代码重复,它是这样的:
struct foo
{
const return_type& get(void) const
{
// fancy pants code that you definitely
// don't want to repeat
return theValue; // and got it
}
return_type& get(void)
{
// well-defined: Add const to *this,
// call the const version, then
// const-cast to remove const (because
// *this is non-const, this is ok)
return const_cast<return_type&>(static_cast<const foo&>(*this).get());
}
};
const_cast
也用于删除volatile
修饰符,正如这篇(有争议的)文章中所实施的那样:
我同意您的说法,即其正常使用是因为您需要隐藏“设计缺陷”。
IME 的典型使用场景之一是当您尝试将 C++ 连接到现有 C 代码时。许多现有的 C 代码char *
即使在未修改字符串的情况下也采用 C 字符串,而它们通常表示为const char *
在 C++ 中转换为 a 的东西。这是您通常使用 const_cast 解决的两种语言之间的阻抗不匹配。当然,您最好非常确定您正在与之交互的代码不会对修改传入的数据产生任何可爱的想法。
我会说这是新编写的代码中的代码气味,但对于与旧的 C 和 C++ 代码的接口,这是必要的邪恶。也就是说,我会非常警惕需要const_cast
任何非 POD 对象的代码,因为这通常是一个应该在设计级别而不是代码级别解决的问题。
一种合法的用途(在我看来)是std::set
迭代器。它们总是const
,以防止更改集合中使用的密钥。更改密钥会破坏集合的内部结构并导致未定义的行为。
但是,只要密钥不更改,就可以安全地更改对象中的其他数据。
假设你有一个std::set
这样的:
std::set<MyObject> some_set;
像这样的课程:
class MyObject {
public:
MyObject(const std::string &key)
: key_(key) {}
bool operator<(const MyObject &other) const {
return key_ < other.key_;
}
private:
// ...
// <some other data>
// ...
const std::string key_;
};
在上面的例子中,key 已经是 const 了,所以即使修改了对象,也不能破坏集合的内部结构。
通常您只能从const
集合迭代器中获取引用:
const MyObject &object = *some_set_iterator;
但是由于 key 是const
,所以const_cast
对取消引用的迭代器是安全的:
MyObject &object = const_cast<MyObject &>(*some_set_iterator);
一个非常合理的用法是当您同时拥有 const 和非 const api(分别用于 const 和非 const 对象)时,如
class Bar {
const SomeType& foo() const;
SomeType& foo();
}
然后由于我们不想在我们经常使用的两个函数中重复代码
class Bar {
SomeType& foo() {
//Actual implementation
}
const SomeType& foo() const {
return const_cast<Bar*>(this)->foo();
}
};
这当然是假设 foo 没有做违反 const 语义的事情。
是的,当然,当您的调用代码无法修改且 const 不正确时。应该注意的是,您应该只在调用您确定不会修改您的数据的函数时使用它!
c++ 入门(第 5 版)书中有一个 const_cast 用法示例。下面的函数返回对 const 字符串的引用
// return a reference to the shorter of two strings
const string &shorterString(const string &s1, const string
&s2)
{
return s1.size() <= s2.size() ? s1 : s2;
}
这本书然后提到了我们想要一个非常量引用的情况。
我们可以在一对非常量字符串参数上调用该函数,但我们会得到一个对 const 字符串的引用作为结果。我们可能想要一个更短的字符串版本,当给定非常量参数时,它会产生一个简单的引用。我们可以使用 const_cast 编写这个版本的函数:
string &shorterString(string &s1, string &s2)
{
auto &r = shorterString(const_cast<const string&>(s1),
const_cast<const string&>(s2));
return const_cast<string&>(r);
}
此版本通过将其参数转换为对 const 的引用来调用更短字符串的 const 版本。该函数返回对 const 字符串的引用,我们知道该字符串绑定到我们原始的非常量参数之一。因此,我们知道在返回中将该字符串转换回纯字符串& 是安全的。
根据这本书,如果我们知道可以安全施放,就应该使用它。