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

时间:2012-02-10 20:12:25

标签: c++ forward-declaration language-lawyer

C ++规范中允许哪些内容?这很酷。我想知道这是怎么说的。我没有意识到规范允许指向未定义类型的指针。

class T;

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

4 个答案:

答案 0 :(得分:4)

在将指针转换为不相关的类型(char*除外)之后,您唯一允许的操作将被强制转换为原始指针类型。

@cli_hlt打败了我提供这个部分。

这是规则本身:

  

可以将对象指针显式转换为不同类型的对象指针。   当“指向v的指针”的prvalue T1转换为“指向 cv T2的指针”时,结果为{ {1}}如果static_cast<cv T2*>(static_cast<cv void*>(v))T1都是标准布局类型(3.9),且T2的对齐要求不比T2更严格,或者类型为T1。转换类型的prvalue   “指向void的指针”指向T1的指针“(其中T2T1是对象类型,T2的对齐要求为否比T2更严格,并返回其原始类型产生原始指针值。任何其他此类指针转换的结果都未指定。

严格别名规则禁止通过不相关的类型访问对象。见https://stackoverflow.com/a/7005988/103167

与您的问题有些相关的另一条规则见5.4节:

  

使用强制转换符号的强制转换操作数可以是“指向不完整类类型的指针”类型的prvalue。 使用强制转换表示法的强制类型转换的目标类型可以是“指向不完整类类型的指针”如果操作数和目标类型都是类类型且一个或两个都不完整,则未指定是否{{即使存在继承关系,也使用1}}或T1解释   两个班级之间。

答案 1 :(得分:4)

您正在做什么可能合法,但这取决于class T的实际定义,因此我们无法根据您显示的代码确定。

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

  

虽然对可以用它们做什么有限制,但允许指向不完整类型的指针。

这些限制列在§3.2/ 4中:

  

如果符合以下条件,则类型T必须完整:

     
      
  • 定义了T类型的对象,或
  •   
  • 声明了类型为T的非静态类数据成员,或
  •   
  • T用作 new-expression 中的对象类型或数组元素类型,或
  •   
  • 左值转换应用于引用T类型的对象的glvalue,或
  •   
  • 将表达式(隐式或显式)转换为类型T
  •   
  • 表达式不是空指针常量,并且具有void*以外的类型,将使用隐式转换转换为指向T的类型指针或对T的引用, dynamic_caststatic_cast
  •   
  • 类成员访问运算符应用于类型T
  • 的表达式   
  • typeid运算符或sizeof运算符应用于T类型的操作数,或
  •   
  • 定义或调用类型为T的返回类型或参数类型的函数,或
  •   
  • 定义了类型为T的基类,或
  •   
  • 分配了T类型的左值,或
  •   
  • 类型Talignof表达式的主题,或
  •   
  • 异常声明的类型为T,对T的引用或指向T的指针。
  •   

第6个子弹在此处出现,正如我们在§5.2.10/ 7中所见,指针类型之间的reinterpret_cast是根据static_cast定义的:< / p>

  

可以将对象指针显式转换为不同类型的对象指针。当“指向v的指针”的prvalue T1转换为“指向cv T2的指针”时,如果static_cast<cv T2*>(static_cast<cv void*>(v)) T1,结果为T2 T2T1是标准布局类型,void的对齐要求不比T1更严格,或者两种类型都是T2。将“指向T1”的类型的prvalue转换为“指向T2”的类型(其中T2T1是对象类型,{{reinterpret_cast的对齐要求1}}不比static_cast更严格,并且返回其原始类型会产生原始指针值。任何其他此类指针转换的结果都未指定。

但是因为void* T首先到T然后到实际结果指针类型,所以第6个子弹不适用。

所以,到目前为止,尽管int是一个不完整的类型,你仍处于合法领域。但是,如果事实证明{{1}}不是标准布局类型或者比{{1}}具有更严格的对齐要求,则§5.2.10/ 7中的最后一句成立并且您正在调用UB

答案 2 :(得分:2)

第5.2.10(7)节针对您的案例(自ISO / IEC14882:1998(E)以及2011年FDIS)。

答案 3 :(得分:0)

我不确定你认为被允许的是什么。保证您可以reinterpret_cast从一个指针类型到足够大的其他指针类型并再次返回到原​​始类型,并且将是原始指针。其规范见5.2.10 [expr.reinterpret.cast]。也就是说,保证以下功能:

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

我们本周早些时候讨论了这个话题:如果Death Station 9000实现(这将是一个符合C ++的实现,但也试图打破用户代码,只要它允许这样做)XORs位如果reinterpret_cast<T>(x)中涉及的类型不涉及char,那么在程序执行开始时随机选择的位模式的指针模式将是允许的实现。大家一致认为这是可以的。