简体   繁体   English

C ++标准在哪里允许指向未定义类型的指针?

[英]Where does the C++ standard allow pointers to undefined types?

Where in the C++ spec is this allowed? 这在C ++规范中的何处允许? It's cool. 这个很酷。 I want to know how this is spec'd. 我想知道这是如何规范的。 I didn't realize the spec allowed having a pointer to a undefined type. 我没有意识到规范允许使用指向未定义类型的指针。

class T;

int main(int argc, char* argv[])
{
   int x;
   T* p = reinterpret_cast<T*>(&x);
   return 0;
}

The only thing you're allowed to do after casting a pointer to an unrelated type (other than char* ), is cast back to the original pointer type. 在将指针强制转换为不相关的类型( char*除外)之后,唯一要做的事情就是将其强制转换回原始指针类型。

@cli_hlt beat me to providing the section. @cli_hlt击败了我提供此部分。

Here's the rule itself: 这是规则本身:

An object pointer can be explicitly converted to an object pointer of a different type. 可以将对象指针显式转换为其他类型的对象指针。 When a prvalue v of type "pointer to T1 " is converted to the type "pointer to cv T2 ", the result is static_cast<cv T2*>(static_cast<cv void*>(v)) if both T1 and T2 are standard-layout types (3.9) and the alignment requirements of T2 are no stricter than those of T1 , or if either type is void . 当prvalue v型“指针的T1 ”被转换为类型“指针cv T2 ”,结果是static_cast<cv T2*>(static_cast<cv void*>(v))如果两个T1T2是标准-layout类型(3.9)和T2的对齐要求并不比T1严格,或者如果任一类型都是void Converting a prvalue of type "pointer to T1 " to the type "pointer to T2 " (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1 ) and back to its original type yields the original pointer value. 转换类型的prvalue“指针T1 ”的类型“指针T2 ”(其中T1T2是对象类型,并且其中的对准要求T2是不严格的比的T1 ),并返回到其原始类型产生的原始指针值。 The result of any other such pointer conversion is unspecified. 未指定任何其他此类指针转换的结果。

The strict aliasing rule prohibits access to an object through an unrelated type. 严格的别名规则禁止通过无关类型访问对象。 See https://stackoverflow.com/a/7005988/103167 参见https://stackoverflow.com/a/7005988/103167

Another rule somewhat related to your question is found in section 5.4: 在第5.4节中找到了与您的问题有些相关的另一条规则:

The operand of a cast using the cast notation can be a prvalue of type "pointer to incomplete class type". 使用强制转换表示法的强制转换操作数可以是“指向不完整类类型的指针”类型的prvalue。 The destination type of a cast using the cast notation can be "pointer to incomplete class type" If both the operand and destination types are class types and one or both are incomplete, it is unspecified whether the static_cast or the reinterpret_cast interpretation is used, even if there is an inheritance relationship between the two classes. 使用 static_cast符号的static_cast目标类型可以是“指向不完整类类型的指针”如果操作数和目标类型都是类类型,并且一个或两个都不完整,则不确定是否使用static_castreinterpret_cast解释,甚至如果两个类之间存在继承关系。

What you're doing may be legal, but that depends on the real definition of class T , so we can't know for sure based on the code you've shown. 您正在执行的操作可能是合法的,但这取决于class T的实际定义,因此根据您显示的代码我们不确定。

Starting with C++11 §3.9.2/3: 从C ++ 11§3.9.2/ 3开始:

Pointers to incomplete types are allowed although there are restrictions on what can be done with them. 尽管可以使用不完整类型的指针进行限制,但仍可以使用它们。

Those restrictions are listed in §3.2/4: 这些限制在§3.2/ 4中列出:

A class type T must be complete if: 如果满足以下条件,则类类型T必须是完整的:

  • an object of type T is defined, or 定义了类型T的对象,或
  • a non-static class data member of type T is declared, or 声明了类型T的非静态类数据成员,或者
  • T is used as the object type or array element type in a new-expression , or Tnew-expression中用作对象类型或数组元素类型,或者
  • an lvalue-to-rvalue conversion is applied to a glvalue referring to an object of type T , or 左值到右值的转换应用于引用类型T的对象的glvalue,或者
  • an expression is converted (either implicitly or explicitly) to type T , or 表达式将(隐式或显式)转换为类型T ,或者
  • an expression that is not a null pointer constant, and has type other than void* , is converted to the type pointer to T or reference to T using an implicit conversion, a dynamic_cast or a static_cast , or 这不是一个空指针常量,并且具有比其他类型的表达式void* ,被转换为类型指针T或参考T使用的隐式转换,一个dynamic_caststatic_cast ,或
  • a class member access operator is applied to an expression of type T , or 类成员访问运算符应用于类型T的表达式,或者
  • the typeid operator or the sizeof operator is applied to an operand of type T , or typeid运算符或sizeof运算符应用于类型T的操作数,或者
  • a function with a return type or argument type of type T is defined or called, or 定义或调用了返回类型或参数类型为T的函数,或者
  • a class with a base class of type T is defined, or 定义了具有T类型的基类的类,或者
  • an lvalue of type T is assigned to, or 将类型T的左值分配给,或
  • the type T is the subject of an alignof expression, or 类型Talignof表达式的主题,或者
  • an exception-declaration has type T , reference to T , or pointer to T . 异常声明的类型为T ,对T引用或对T指针。

The 6th bullet appears pertinent here, as we can see in §5.2.10/7 that a reinterpret_cast between pointer types is defined in terms of static_cast : 第六届子弹出现此相关的,因为我们可以在§5.2.10/ 7看到, reinterpret_cast指针类型之间的形式定义static_cast

An object pointer can be explicitly converted to an object pointer of a different type. 可以将对象指针显式转换为其他类型的对象指针。 When a prvalue v of type “pointer to T1 ” is converted to the type “pointer to cv T2 ”, the result is static_cast<cv T2*>(static_cast<cv void*>(v)) if both T1 and T2 are standard-layout types and the alignment requirements of T2 are no stricter than those of T1 , or if either type is void . 当将“指向T1指针”的prvalue v转换为“指向T2指针”时,如果T1T2都是标准的,则结果为static_cast<cv T2*>(static_cast<cv void*>(v)) -layout类型和的对准要求T2是不严格的比的T1 ,或者如果任一类型是void Converting a prvalue of type “pointer to T1 ” to the type “pointer to T2 ” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1 ) and back to its original type yields the original pointer value. 转换类型的prvalue“指针T1 ”的类型“指针T2 ”(其中T1T2是对象类型,并且其中的对准要求T2是不严格的比的T1 ),并返回到其原始类型产生的原始指针值。 The result of any other such pointer conversion is unspecified. 未指定任何其他此类指针转换的结果。

But because reinterpret_cast static_cast s to void* first, then to the real resulting pointer type, that 6th bullet doesn't apply. 但是因为reinterpret_cast static_cast s首先设置为void*然后再设置为实际的指针类型,所以第6个项目符号不适用。

So, so far you're still in legal territory, despite T being an incomplete type. 因此,到目前为止,尽管T是不完整的类型,但您仍处于合法范围内。 However, if it turns out that T is not a standard-layout type or has stricter alignment requirements than int , then the last sentence in §5.2.10/7 holds true and you're invoking UB. 但是,如果事实证明T不是标准布局类型或比int更严格的对齐要求,则第5.2.10 / 7节中的最后一句话成立,您正在调用UB。

适用于您的情况的第5.2.10(7)节(根据ISO / IEC14882:1998(E),以及2011 FDIS中的规定)。

I'm not sure what you perceive as being allowed. 我不确定您认为允许什么。 There is a guarantee that you can reinterpret_cast from one pointer type to a sufficiently big other pointer type and back to the original type again and will be the original pointer. 可以保证您可以从一个指针类型reinterpret_cast到足够大的其他指针类型,然后再次返回到原​​始类型,并将成为原始指针。 The specification for this is in 5.2.10 [expr.reinterpret.cast]. 规范在5.2.10 [expr.reinterpret.cast]中。 That is, the following is guaranteed to work: 即,保证以下工作:

T* ptr = ...;
S* sptr = reinterpret_cast<S*>(ptr);
T* tptr = reinterpret_cast<T*>(sptr);
assert(ptr == tptr);

We had an out of session discussion earlier this week on this topic: if the Death Station 9000 implementation (which would be a conforming implementation of C++ but also tries to break user code wherever it is allowed to do so) XORs the bit pattern of the pointer with a bit pattern randomly chosen at the beginning of the program execution, would this be a permissible implementation if the types involved in the reinterpret_cast<T>(x) are not involving char . 我们在本周早些时候就该主题进行了闭门讨论:如果Death Station 9000实现(这是C ++的一致实现,但也尝试在允许这样做的地方打破用户代码),XOR会使用如果指针在程序执行开始时具有随机选择的位模式,则如果reinterpret_cast<T>(x)中涉及的类型不涉及char ,则这将是允许的实现。 The consensus was that this would be OK. 一致认为这是可以的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM