const_cast<> 的正确用法

发布于 2024-08-29 11:36:22 字数 211 浏览 7 评论 0 原文

作为一个常见规则,在 C++ 代码中使用 const_cast<>() 通常被认为是一种不好的做法,因为它(大多数时候)暴露了设计中的缺陷。

虽然我完全同意这一点,但我想知道在什么情况下使用 const_cast<>() 是ok以及唯一的解决方案

你们能给我一些您知道/遇到过的例子吗?

非常感谢。

As a common rule, it is very often considered a bad practice to use const_cast<>() in C++ code as it reveals (most of the time) a flaw in the design.

While I totally agree with this, I however wonder what are the cases were using const_cast<>() is ok and the only solution.

Could you guys please give me some examples you know/you encountered ?

Thank you very much.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

小猫一只 2024-09-05 11:36:22

它几乎被设计为仅与非 const 正确的遗留 API 一起使用,即与您无法更改且具有非 const 接口但实际上不会改变接口上任何内容的函数一起使用

it is pretty much designed to be only used with legacy APIs that are not const correct i.e. with a function you can't change that has non const interface but doesn't actually mutate anything on the interface

旧时模样 2024-09-05 11:36:22

正如其他人所说,它的主要目的是从对象中删除 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());
    }
};

Like others have said, its primary purpose is to remove const from objects in order to pass to non-const correct functions you know won't modify the argument.

There is a trick (by Meyers?) to avoid code duplication, and it goes like this:

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());
    }
};
疧_╮線 2024-09-05 11:36:22

const_cast 还用于删除 volatile 修饰符,如这篇(有争议的)文章中的实践:

const_cast is also used to remove volatile modifiers, as put into practice in this (controversed) article:

http://www.drdobbs.com/184403766

执笔绘流年 2024-09-05 11:36:22

我同意你的说法,即它的正常使用是因为你需要隐藏“设计缺陷”。

IME 的典型使用场景之一是当您尝试将 C++ 与现有 C 代码连接时。许多现有的 C 代码将 C 字符串视为 char *,即使字符串未修改也是如此,而它们通常表示为在 C++ 中转换为 const char * 的内容。这是两种语言之间的阻抗不匹配,通常可以使用 const_cast 来解决。当然,您最好非常确保您所连接的代码不会获得任何有关修改传入数据的可爱想法。

我想说,这是一段新的代码味道编写的代码,但对于与旧的 C 和 C++ 代码交互,这是一个必要的邪恶。也就是说,我对任何非 POD 对象都需要 const_cast 的代码非常警惕,因为这通常是一个应该在设计级别而不是代码级别解决的问题。

I agree with your statement that its normal use is because you need to hide a 'design flaw'.

IME one of the typical usage scenarios is when you try to interface C++ to existing C code. A lot of existing C code takes C strings as char * even when the string is not modified whereas they're usually represented as something that converts to a const char * in C++. That's an impedance mismatch between the two languages that you would normally solve by using a const_cast. Of course you'd better be very sure that the code you're interfacing with doesn't get any cute ideas about modifying the data that's being passed in.

I would say that it's a code smells in newly written code, but for interfacing with older C and C++ code, it's an necessary evil. That said, I would be extremely wary of code that requires const_cast for any non-POD objects as that is normally a problem that should be solved at the design level and not the code level.

我不是你的备胎 2024-09-05 11:36:22

(在我看来)一种合法的用途是使用 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_;
};

在上面的例子中,键已经是 const,所以即使你修改了对象,你不能破坏集合的内部结构。

通常,您只能从 set 迭代器中获取 const 引用:

const MyObject &object = *some_set_iterator;

但由于键是 const,因此可以安全地 const_cast 取消引用的迭代器:

MyObject &object = const_cast<MyObject &>(*some_set_iterator);

One legitimate use (in my opinion) is with std::set iterators. They are always const, in order to prevent changing the key used in the set. Changing the key would break the internal structure of the set and cause undefined behavior.

However, as long as the key doesn't change it's safe to change other data in the object.

Let's say you have an std::set like this:

std::set<MyObject> some_set;

And a class like this:

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_;
};

In the above example, the key is already const, so even if you modify the object, you cannot break the internal structure of the set.

Normally you can only get a const reference out of a set iterator:

const MyObject &object = *some_set_iterator;

But since the key is const, it's safe to const_cast the dereferenced iterator:

MyObject &object = const_cast<MyObject &>(*some_set_iterator);
清风夜微凉 2024-09-05 11:36:22

一个非常合法的用法是当您同时拥有 const 和非 const api(分别用于 const 和非 const 对象)时,如

class Bar {
   const SomeType& foo() const; 
   SomeType& foo();
}

Then 中所示,因为我们不想在我们经常使用的两个函数中重复代码

class Bar {
   SomeType& foo() {
      //Actual implementation 
   }
   const SomeType& foo() const {
        return const_cast<Bar*>(this)->foo();
   }
};

这当然是假设foo 不会做任何违反 const 语义的事情。

One very legitimate use of this is when you have both a const and non const api (for const and non const objects respectively) as in

class Bar {
   const SomeType& foo() const; 
   SomeType& foo();
}

Then since we don't want to duplicate the code in both functions we often use

class Bar {
   SomeType& foo() {
      //Actual implementation 
   }
   const SomeType& foo() const {
        return const_cast<Bar*>(this)->foo();
   }
};

This is of course assuming that foo does not do something that violates the const semantics.

缺⑴份安定 2024-09-05 11:36:22

是的,当然,当您无法修改且 const 不正确的调用代码时。应该注意的是,您应该仅将它与对您确定不会修改数据的函数的调用一起使用!

Yes of course, when your calling code that you can't modify and isn't const correct. It should be noted that you should only use it with calls to functions that you know for certain won't modify your data!

雪若未夕 2024-09-05 11:36:22

C++ Primer(5th Edition)一书中有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 字符串的引用作为结果。我们可能想要
拥有一个 ShortString 版本,当给定非常量时
参数,将产生一个简单的参考。我们可以写这个版本
我们的函数使用 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 引用的参数。该函数返回一个引用
一个常量字符串,我们知道它绑定到我们的原始字符串之一,
非常量参数。因此,我们知道转换该字符串是安全的
回到纯字符串&在回报中。

根据这本书,如果我们知道它是安全的,就应该使用它。

There is an example of const_cast usage in c++ primer(5th edition) book.
Below function returns reference to const string

// 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;
}

The book then mentions the case when we want a non const reference.

We can call the function on a pair of nonconst string arguments, but
we’ll get a reference to a const string as the result. We might want
to have a version of shorterString that, when given nonconst
arguments, would yield a plain reference. We can write this version of
our function using a 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);
}

This version calls the const version of shorterString by casting its
arguments to references to const. That function returns a reference to
a const string, which we know is bound to one of our original,
nonconst arguments. Therefore, we know it is safe to cast that string
back to a plain string& in the return.

According to the book, it should be used if we know it is safe to cast.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文