2012-06-15 60 views
4

我偶然发现了一些看起来是正确的代码。 它应该提供一个公共的,不可变的指针,同时使可修改的非const指针保持私有状态。指针是否可以强制转换常量调用未定义的行为?

奇怪的是,这段代码在SN C++编译器(用于PlayStation 3)上打破了,但在GCC上运行良好。在SN C++上,data将指向虚假值,而m_data将按预期工作。

代码中的问题:

#include <cstdint> 

class Foo 
{ 
    public: 
     Foo() : data((const std::uint8_t* const&)m_data) 
     { 
     m_data = nullptr; // Set later in some other member function. 
     } 

     const std::uint8_t* const &data; 

    private: 
     std::uint8_t* m_data; 
}; 

这段代码调用未定义的行为?据我所知,铸造到像这样的参考将转换*reinterpret_cast<const std::uint8_t* const*>(&m_data)(const std::uint8_t* const&)m_data

测试用例:

Foo* new_foo() { return new Foo; } 

并查看生成的拆卸。请注意,它是带有32位长和指针的PowerPC 64位。

SN C++:ps3ppusnc -o test-sn.o -O3 -c test.cpp

0000000000000000 <._Z7new_foov>: 
    0: f8 21 ff 81  stdu r1,-128(r1)  # ffffff80 
    4: 7c 08 02 a6  mflr r0 
    8: f8 01 00 90  std  r0,144(r1)  # 90 
    c: fb e1 00 78  std  r31,120(r1)  # 78 
    10: 38 60 00 08  li  r3,8 
    14: 3b e0 00 00  li  r31,0 
    18: 48 00 00 01  bl  18 <._Z7new_foov+0x18> 
    1c: 60 00 00 00  nop 
    20: 2c 03 00 00  cmpwi r3,0 
    24: 41 82 00 38  beq  5c <._Z7new_foov+0x5c> 
    28: 30 81 00 70  addic r4,r1,112  # 70 
    2c: 93 e3 00 04  stw  r31,4(r3) <-- Set m_data to r31 (0). 
    30: 60 7f 00 00  ori  r31,r3,0 
    34: 90 83 00 00  stw  r4,0(r3) <-- Set data to r4 (r1 + 112 (On stack)?!) 
    38: 63 e3 00 00  ori  r3,r31,0 
    3c: e8 01 00 90  ld  r0,144(r1)  # 90 
    40: 7c 08 03 a6  mtlr r0 
    44: eb e1 00 78  ld  r31,120(r1)  # 78 
    48: 38 21 00 80  addi r1,r1,128  # 80 
    4c: 4e 80 00 20  blr 

GCC 4.1.1:ppu-lv2-g++ -o test-gcc.o -O3 -c test.cpp

0000000000000000 <._Z7new_foov>: 
    0: 38 60 00 08  li  r3,8 
    4: 7c 08 02 a6  mflr r0 
    8: f8 21 ff 91  stdu r1,-112(r1)  # ffffff90 
    c: f8 01 00 80  std  r0,128(r1)  # 80 
    10: 48 00 00 01  bl  10 <._Z7new_foov+0x10> 
    14: 60 00 00 00  nop 
    18: 7c 69 1b 78  mr  r9,r3 
    1c: 38 00 00 00  li  r0,0 
    20: 39 63 00 04  addi r11,r3,4 <-- Compute address of m_data 
    24: 78 63 00 20  clrldi r3,r3,32  # 20 
    28: 90 09 00 04  stw  r0,4(r9) <-- Set m_data to r0 (0). 
    2c: e8 01 00 80  ld  r0,128(r1)  # 80 
    30: 38 21 00 70  addi r1,r1,112  # 70 
    34: 91 69 00 00  stw  r11,0(r9) <-- Set data reference to m_data. 
    38: 7c 08 03 a6  mtlr r0 
    3c: 4e 80 00 20  blr 
+2

“发生中断”是什么意思? – Rook

+0

同意Rook,你能提供一个展示破坏行为的最小测试用例吗? –

+3

您在'data'的初始化过程中使用了'm_data',但此时m_data仍未初始化。 – Mohammad

回答

3

你必须在4.4/4通过规范语言打(的C++ 11)但我相信3.10/10是允许的。它表示该对象可能被别名为“类似于该对象的动态类型的类型”。

在这种情况下,对象的动态类型为std::uint8_t*,类似的类型为const std::uint8_t* const。我认为。自己检查4.4/4。

[更新:C++ 03在3.10/15中没有提及“类似”类型,所以可能是您在C++ 03上遇到麻烦,这大概是SNC的工作原理。]

还有第二件事需要检查,即是否可以通过将参考data绑定到尚未初始化的对象(m_data)来初始化它。直观地说,这看起来没问题,因为对未初始化的m_data的引用永远不会转换为右值。无论如何,它很容易修复。

相关问题