使用const_cast来添加恒常性 - 坏主意?

Using const_cast to add const-ness - bad idea?

本文关键字:常性 const cast 添加 使用      更新时间:2023-10-16

众所周知,应避免使用const_cast来消除指针的恒常性。

但是反过来呢?

对于我的用例,我有一个从非常量源缓冲区复制数据(字节)的函数。 我认为一个好的设计决策是根据该源缓冲区完全常量声明参数。

void copyfunction(const char* const data) { ... }

对于如下所示的函数调用,这将导致指针类型错误"const char* const <-> char*"。

void main() {
char sourcebuffer[] = {0x00};
copyfunction(sourcebuffer);
}

当然,现在我可以简单地将sourcebuffer声明为 const,但就我而言,我无法访问该变量,因为它来自不同的代码位置(外部库)。

void main() {
char sourcebuffer[] = {0x00};
copyfunction(const_cast<const char* const>(sourcebuffer));
}

但是,超出的代码会起作用,但它是好的风格(根据我的用例)?

我认为将copyfunction的参数声明为 const 可以确保用户不会修改(只读)指针或源缓冲区本身的位置。 因此,在这种情况下,const_cast只是使函数调用成为可能的必要邪恶,而不是故意删除指针的恒定性......

迎接

你不应该使用const_cast来添加const,因为:

  1. 这是不必要的。T*隐式转换为const T*。您的问题指出char sourcebuffer[] = {0x00}; copyfunction(sourcebuffer);是一个错误,但事实并非如此。

  2. 它可能(尽管不太可能)有害。它可以从指针类型中删除volatile,这不是此处的意图,如果sourcebuffer声明为volatile sourcebuffer[],将导致未定义的行为。

您不应该使用const_cast来添加const因为

  1. 在操作安全的情况下,几乎总是不需要。int*隐含地变成了const int*

  2. 它可以做一些你不想让它做的事情。 它可以剥离volatile,或者让你错过const被添加到变量中的其他地方,而你的const_cast现在默默地剥离它们的事实。

  3. 在需要添加const的情况下,它的使用是危险的,很难推理。

在某些情况下,您需要调用const_cast才能添加不会隐式发生的const

void assign_ptr( int const*& lhs, int const* rhs ) { lhs = rhs; }
int const foo = 7;
int* bar = nullptr;
assign_ptr( const_cast<int const*&>(bar), &foo );
*bar = 2; // undefined behavior!
std::cout << foo << "@" << &foo << "n"; // will print probably 7@something
std::cout << *bar << "@" << bar << "n"; // will print probably 2@same address as above!

上述对assign_ptr的调用只会增加const,但它不会隐式发生。

它的副作用是修改*bar是未定义的行为,因为它修改了声明为const的变量(它使bar,一个int*,指向fooconst int)。

因此,虽然需要const_cast才能编译assign_ptr调用,但这是因为它不安全const_cast并没有使它更安全,它只是隐藏了错误。

这是矩形正方形问题的特定情况。 正方形不是矩形,因为如果您更改正方形的宽度,其高度也会更改,而修改矩形时不会发生这种情况。 同样,int**也不int const**. (请注意,不可变的正方形是一种不可变的矩形;正是突变导致了这个问题。 在指针的情况下,int*const*是一个int const*const*:"更高级别"指针的可变性导致了问题。