使用const_cast的未定义行为 [英] Undefined behaviour with const_cast

查看:291
本文介绍了使用const_cast的未定义行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望有人可以澄清什么是C ++中未定义的行为的含义。给定以下类定义:

 类Foo 
{
public:
explicit Foo int Value):m_Int(Value){}
void SetValue(int Value){m_Int = Value; }

private:
Foo(const Foo& rhs);
const Foo& operator =(const Foo& rhs);

private:
int m_Int;
};

如果我正确理解了下面代码中的两个const_casts引用和指针删除类型为Foo的原始对象的常量,但是任何通过指针或引用修改此对象的尝试都将导致未定义的行为。

  int main()
{
const Foo MyConstFoo(0);
Foo& rFoo = const_cast< Foo&>(MyConstFoo);
Foo * pFoo = const_cast< Foo *>(& MyConstFoo);

//MyConstFoo.SetValue(1); // Error MyConstFoo is const
rFoo.SetValue(2); // Undefined behavior
pFoo-> SetValue(3); //未定义的行为

return 0;令人费解的是,这是为什么这似乎工作,将修改原来的常量(const),这是为什么?。
}


$ b <对象,但甚至不提示我有警告,通知我,这种行为是未定义的。我知道,const_casts,广义上来说,皱眉,但我可以想象一个情况下,C风格的转换可能导致一个const_cast可能会发生没有被注意到的意识,例如:

  Foo& rAnotherFoo =(Foo&)MyConstFoo; 
Foo * pAnotherFoo =(Foo *)& MyConstFoo;

rAnotherFoo-> SetValue(4);
pAnotherFoo-> SetValue(5);

在什么情况下这种行为会导致致命的运行时错误?有没有一些编译器设置,我可以设置警告这个(可能)危险的行为?



注意:我使用MSVC2008。


<我希望有人能够澄清什么是C ++中未定义的行为的意思。


技术上来说,未定义的行为意味着语言不会定义任何语义。



在实践中,这通常意味着不要这样做;它会在编译器执行优化或其他原因时中断。


让我困惑的是为什么这看起来工作,并会修改原来的const对象,但是甚至不提示我有警告通知


在此特定示例中,尝试修改任何不可变对象可能看起来工作或者它可以覆盖不属于程序或属于某一其他对象的[部分]的存储器,因为非可变对象可能已经在编译时被优化掉了,或者它可能存在一些只读



可能导致这些事情发生的因素太复杂,无法列出。考虑取消引用未初始化的指针(也是UB)的情况:你随后使用的对象将具有一些任意的内存地址,这取决于在指针位置的内存中发生的任何值; 值可能依赖于先前的程序调用,在同一程序中的先前工作,用户提供的输入的存储等。试图合理化调用未定义行为的可能结果是不可行的,因此,再次,


令人费解的是,为什么会这样呢?看起来工作,并将修改原始的const对象,但是甚至不提示我通知我这个行为是未定义的警告。


作为另一个复杂因素,编译器不需要来诊断(发出警告/错误)未定义的行为,因为调用未定义行为的代码不同于代码是错误的(即明确非法)。在许多情况下,编译器甚至不能检测UB,所以这是一个程序员负责正确编写代码的区域。



类型系统—包括 const 关键字&mdash的存在和语义;提供基本的保护,防止编写代码,打破;一个C ++程序员应该始终知道颠覆这个系统。例如通过破解 const ness—


我可以想象一种情况,即缺乏意识的C风格cast可以导致 const_cast 可能在没有被注意到的情况下发生。


绝对。如果警告级别设置得足够高,一个合理的编译器可以选择警告你这个,但它不必,也不可能。一般来说,这是一个很好的原因,为什么C风格的演员被皱眉,但他们仍然支持向后兼容C.它只是其中一个不幸的事情。


I was hoping that someone could clarify exactly what is meant by undefined behaviour in C++. Given the following class definition:

class Foo
{
public:
    explicit Foo(int Value): m_Int(Value) { }
    void SetValue(int Value) { m_Int = Value; }

private:
    Foo(const Foo& rhs);
    const Foo& operator=(const Foo& rhs);

private:
    int m_Int;
};

If I've understood correctly the two const_casts to both a reference and a pointer in the following code will remove the const-ness of the original object of type Foo, but any attempts made to modify this object through either the pointer or the reference will result in undefined behaviour.

int main()
{
    const Foo MyConstFoo(0);
    Foo& rFoo = const_cast<Foo&>(MyConstFoo);
    Foo* pFoo = const_cast<Foo*>(&MyConstFoo);

    //MyConstFoo.SetValue(1);   //Error as MyConstFoo is const
    rFoo.SetValue(2);           //Undefined behaviour
    pFoo->SetValue(3);          //Undefined behaviour

    return 0;
}

What is puzzling me is why this appears to work and will modify the original const object but doesn't even prompt me with a warning to notify me that this behaviour is undefined. I know that const_casts are, broadly speaking, frowned upon, but I can imagine a case where lack of awareness that C-style cast can result in a const_cast being made could occur without being noticed, for example:

Foo& rAnotherFoo = (Foo&)MyConstFoo;
Foo* pAnotherFoo = (Foo*)&MyConstFoo;

rAnotherFoo->SetValue(4);
pAnotherFoo->SetValue(5);

In what circumstances might this behaviour cause a fatal runtime error? Is there some compiler setting that I can set to warn me of this (potentially) dangerous behaviour?

NB: I use MSVC2008.

解决方案

I was hoping that someone could clarify exactly what is meant by undefined behaviour in C++.

Technically, "Undefined Behaviour" means that the language defines no semantics for doing such a thing.

In practice, this usually means "don't do it; it can break when your compiler performs optimisations, or for other reasons".

What is puzzling me is why this appears to work and will modify the original const object but doesn't even prompt me with a warning to notify me that this behaviour is undefined.

In this specific example, attempting to modify any non-mutable object may "appear to work", or it may overwrite memory that doesn't belong to the program or that belongs to [part of] some other object, because the non-mutable object might have been optimised away at compile-time, or it may exist in some read-only data segment in memory.

The factors that may lead to these things happening are simply too complex to list. Consider the case of dereferencing an uninitialised pointer (also UB): the "object" you're then working with will have some arbitrary memory address that depends on whatever value happened to be in memory at the pointer's location; that "value" is potentially dependent on previous program invocations, previous work in the same program, storage of user-provided input etc. It's simply not feasible to try to rationalise the possible outcomes of invoking Undefined Behaviour so, again, we usually don't bother and instead just say "don't do it".

What is puzzling me is why this appears to work and will modify the original const object but doesn't even prompt me with a warning to notify me that this behaviour is undefined.

As a further complication, compilers are not required to diagnose (emit warnings/errors) for Undefined Behaviour, because code that invokes Undefined Behaviour is not the same as code that is ill-formed (i.e. explicitly illegal). In many cases, it's not tractible for the compiler to even detect UB, so this is an area where it is the programmer's responsibility to write the code properly.

The type system — including the existence and semantics of the const keyword — presents basic protection against writing code that will break; a C++ programmer should always remain aware that subverting this system — e.g. by hacking away constness — is done at your own risk, and is generally A Bad Idea.™

I can imagine a case where lack of awareness that C-style cast can result in a const_cast being made could occur without being noticed.

Absolutely. With warning levels set high enough, a sane compiler may choose to warn you about this, but it doesn't have to and it may not. In general, this is a good reason why C-style casts are frowned upon, but they are still supported for backwards compatibility with C. It's just one of those unfortunate things.

这篇关于使用const_cast的未定义行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆