const_cast安全吗?


92

我找不到有关的太多信息const_cast。我可以找到的唯一信息(堆栈溢出)是:

const_cast<>()用于添加/可变的删除常量(岬)(或挥发性岬)。

这让我感到紧张。可以使用const_cast导致意外行为的行为吗?如果是这样,该怎么办?

或者,什么时候可以使用const_cast


4
最重要的答案忽略了一些可能非常显而易见但值得说明的问题:仅当您尝试const通过指定的const引用/指针修改原始对象时,此问题才变得不安全。相反,如果您只是const_cast想解决一个糟糕的(或者在我的情况下,是懒惰的)规范的API,该API只接受一个非const引用,但只会在const方法中使用……毫无问题。
underscore_d

1
@underscore_d:这个问题(和答案)的更精确的版本涵盖了以下内容:只要未实际修改const定义的对象,是否可以将const抛弃掉?
彼得·科德斯

Answers:


88

const_cast仅当您强制转换最初不是的变量时才是安全的const。例如,如果您有一个接受参数a的函数const char *,并且传入了modifiable char *,则可以安全地const_cast将该参数返回给a char *并对其进行修改。但是,如果原始变量实际上是const,则使用const_cast会导致未定义的行为。

void func(const char *param, size_t sz, bool modify)
{
    if(modify)
        strncpy(const_cast<char *>(param), sz, "new string");
    printf("param: %s\n", param);
}

...

char buffer[16];
const char *unmodifiable = "string constant";
func(buffer, sizeof(buffer), true);  // OK
func(unmodifiable, strlen(unmodifiable), false); // OK
func(unmodifiable, strlen(unmodifiable), true);  // UNDEFINED BEHAVIOR

9
这不是真的。C ++标准。§7.1.​5.1/4 says Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior 任何尝试!没有关于原始变量的文字。
阿列克谢·马里斯托夫

20
@Alexey:原始变量与指向或引用的内容有关。您可以对非const对象进行const引用,因此,将其强制转换为可写引用是明确定义的行为,因为所引用的对象实际上不是const。
小狗

43
@Alexey Malistov:否。“对象”是指内存中实际占用的存储区域(第1.7节)。将const引用到非const对象不会使该对象成为const。仅在使用const 引用参数(而不是 const指针参数)的情况下,才允许编译器以静默方式进行复制(第5.2.2./5节);这里不是这种情况。
亚当·罗森菲尔德

8
“但是,如果原始变量实际上是const,那么使用const_cast将导致未定义的行为”
Lightness Races in Orbit

7
不是 UB使用const_cast删除const从最初宣称的东西const。但是实际上尝试写该对象 UB。只要您阅读就可以了,并且const_cast本身不会导致UB。这是一个可怕的想法,但它本质上不是UB。
Jesper Juhl

35

我可以想到const_cast是安全和有用的两种情况(可能还有其他有效情况)。

一种是当您具有const实例,引用或指针,并且想要将指针或引用传递给非const正确的API,但是您确定不会修改该对象。您可以const_cast指针并将其传递给API,并相信它不会真正改变任何东西。例如:

void log(char* text);   // Won't change text -- just const-incorrect

void my_func(const std::string& message)
{
    log(const_cast<char*>(&message.c_str()));
}

另一个是如果您使用的是不实现“可变”功能的较旧的编译器,并且您想创建一个逻辑上为const而不是按位const的类。您可以在const方法中const_cast'this'并修改类的成员。

class MyClass
{
    char cached_data[10000]; // should be mutable
    bool cache_dirty;        // should also be mutable

  public:

    char getData(int index) const
    {
        if (cache_dirty)
        {
          MyClass* thisptr = const_cast<MyClass*>(this);
          update_cache(thisptr->cached_data);
        }
        return cached_data[index];
    }
};

这...似乎没有回答这个问题。他问是否const_cast会导致不确定的行为,而不是它的有用用途
Michael Mrozek 2014年

13
从以下问题开始:“或者,什么时候可以使用const_cast?”
弗雷德·拉尔森

如“何时未定义”中所述;他没有在寻找有用的例子
Michael Mrozek

我们只能坚持提出问题的字母。基于此,对的使用说明的提出const_cast是有效的答案。没有he问题,因为问题本身就是问题。
truthadjustr

24

我很难相信这是您可以找到的有关const_cast 的唯一信息。引用第二个Google热门歌曲

如果舍弃已明确声明为const的对象的constness,并尝试对其进行修改,则结果是不确定的。

但是,如果丢弃没有明确声明为const的对象的constness,则可以安全地对其进行修改。


Grrrreaat答案,将此答案此答案结合起来,您将获得整个图片。
bobobobo

嗯。关于答案中的第二条语句,请问您对于没有首先声明为const的对象有什么“ const”性?
hAcKnRoCk

有很多方法可以使非常量对象成为const @Iam。例如,将对象作为const-reference参数传递。或将其分配给指向常量的指针。或使用const_cast。或在其上调用const方法。
罗伯·肯尼迪

12

亚当怎么说。const_cast可能有帮助的另一个示例:

struct sample {
    T& getT() { 
        return const_cast<T&>(static_cast<const sample*>(this)->getT()); 
    }

    const T& getT() const { 
       /* possibly much code here */
       return t; 
    }

    T t;
};

我们首先将const添加到指向的类型this,然后调用的const版本getT,然后从返回类型中删除const,这是有效的,因为它t必须是非const(否则,非const版本getT不能被称为)。如果您的函数体很大,并且想要避免多余的代码,这将非常有用。


3
我宁愿使用static强制转换来添加constness:static_cast <const sample *>(this)。当我阅读const_cast时,它意味着代码正在做有潜在危险的事情,因此我尝试避免在可能的情况下使用它。
mfazekas

1
正确,第一个可以是static_cast,甚至可以是(提升的)implicit_cast。我将使用静态投射修复它。感谢
Johannes Schaub-litb

3
我来回走是否const_cast还是static_cast比较好。const_cast只能做你想做的:改变简历限定符。static_cast可以“无声地”执行您不想要的其他操作。但是,第一次强制转换完全是安全的,而且static_cast往往比更加安全const_cast。我认为这种情况const_cast可以更好地传达您的意图,但可以更好地static_cast传达您的行为安全。
大卫·斯通

10

简短的答案是不,这是不安全的。

长答案是,如果您知道足够使用它,那么它应该是安全的。

当您进行转换时,您实际上要说的是:“我知道编译器不知道的东西。” 对于const_cast,您要说的是,“即使此方法接受非const引用或指针,我也知道它不会更改我传递给它的参数。”

因此,如果您确实知道您在使用演员表时声称要知道什么,那么可以使用它。


5

如果您开始修改编译器认为是const的内容,那么您正在破坏线程安全的任何机会。


1
什么?如果你有不可变的(常量)对象,你可以平凡分享他们之间的线程。您的一段代码放弃一致性的那一刻,您将失去所有线程安全性!为什么我为此而沮丧? 感叹
Matt Cruikshank

8
const当然是使代码成为线程安全的有用工具,但它不提供任何保证(除非在编译时常量情况下)。有两个例子:const对象可能具有可变成员,而const指向对象的指针并没有说明该对象本身是否可以更改。
詹姆斯·霍普金

我认为这是一个很好的答案,因为我没有考虑到编译器优化程序在使用单词时的信任和安全感constconst是信任。const_cast打破了信任:(
bobobobo

1
关于可变和线程安全:channel9.msdn.com/posts/…–
MFH

-3
#include <iostream>
using namespace std;

void f(int* p) {
  cout << *p << endl;
}

int main(void) {
  const int a = 10;
  const int* b = &a;

  // Function f() expects int*, not const int*
  //   f(b);
  int* c = const_cast<int*>(b);
  f(c);

  // Lvalue is const
  //  *b = 20;

  // Undefined behavior
  //  *c = 30;

  int a1 = 40;
  const int* b1 = &a1;
  int* c1 = const_cast<int*>(b1);

  // Integer a1, the object referred to by c1, has
  // not been declared const
  *c1 = 50;

  return 0;
}

来源:http : //publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fkeyword_const_cast.htm


由于垃圾邮件链接而引起的投票下降
Trueadjustr
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.