在C++中使用static_cast转换指向数组引用的指针是否合法?

Tho*_*ing 16 c++ arrays casting static-cast type-safety

我有一个T * pValues我想要查看的指针T (&values)[N]

在这个SO答案/sf/answers/184449611/中,建议的方法是

T (&values)[N] = *static_cast<T(*)[N]>(static_cast<void*>(pValues));
Run Code Online (Sandbox Code Playgroud)

我对此的担忧是.在他的例子中,pValues以下面的方式初始化

T theValues[N];
T * pValues = theValues;
Run Code Online (Sandbox Code Playgroud)

我的问题是,如果pValues来自以下任何构造,则构造构造是否合法:

1:

T theValues[N + M]; // M > 0
T * pValues = theValues;
Run Code Online (Sandbox Code Playgroud)

2:

T * pValues = new T[N + M]; // M >= 0
Run Code Online (Sandbox Code Playgroud)

Lih*_*ihO 9

简短的回答:你是对的.只有在pValues类型T[N]的情况下,强制转换是安全的,并且您提到的两种情况(不同大小,动态分配的数组)很可能导致未定义的行为.


关于这种做法的好处static_cast是,一些额外的检查在编译时作出所以如果它似乎你正在做的事情错了,编译器会抱怨它(相比于丑陋的C样式转换,允许你做几乎任何事情),例如:

struct A { int i; };
struct C { double d; };

int main() {
    A a;
    // C* c = (C*) &a; // possible to compile, but leads to undefined behavior
    C* c = static_cast<C*>(&a);
}
Run Code Online (Sandbox Code Playgroud)

会给你: invalid static_cast from type ‘A*’ to type ‘C*’

在这种情况下,您可以转换为void*,从编译时可以进行的检查视图几乎适用于任何事情,反之亦然:void*几乎可以将其转换回任何东西,这使得static_cast在第一时间使用完全无用因为这些检查变得无用.

对于前面的示例:

C* c = static_cast<C*>(static_cast<void*>(&a));
Run Code Online (Sandbox Code Playgroud)

并不比:

C* c = (C*) &a;
Run Code Online (Sandbox Code Playgroud)

并且很可能会导致错误地使用此指针和未定义的行为.


换一种说法:

A arr[N];
A (&ref)[N] = *static_cast<A(*)[N]>(&arr);
Run Code Online (Sandbox Code Playgroud)

很安全,很好.但是一旦你开始滥用,static_cast<void*>就完全没有任何关于实际发生的事情的保证,因为即使是这样的东西:

C *pC = new C;
A (&ref2)[N] = *static_cast<A(*)[N]>(static_cast<void*>(&pC));
Run Code Online (Sandbox Code Playgroud)

成为可能.

  • IMHO静态转换为void*应该是标准的非法. (2认同)