Can a pointer indicate that only changing constness causes undefined behavior?

I came across some kind of code that seems to be correct. It must provide an open, immutable pointer, while maintaining a mutable, non-private private pointer.

Oddly enough, this code crashed on the SN C ++ Compiler (for the PlayStation 3), but it worked fine on GCC. In SN C ++, data will point to dummy values, and m_data will work as intended.

Code in question:

 #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; }; 

Does this code cause undefined behavior? As far as I know, casting to such a link will result in converting (const std::uint8_t* const&)m_data to *reinterpret_cast<const std::uint8_t* const*>(&m_data) .

Test cases:

 Foo* new_foo() { return new Foo; } 

and looking at the generated disassembly. Note that this is a 64-bit version of PowerPC with 32-bit long and index pointers.

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 
+4
source share
1 answer

You will have to fight through the specification language in 4.4 / 4 (from C ++ 11), but I believe that this allows 3.10 / 10. It says that an object can be an alias as "a type similar to the dynamic type of an object."

In this case, the dynamic type of the object is std::uint8_t* , and a similar type is const std::uint8_t* const . I think. Check out 4.4 / 4 for yourself.

[Update: C ++ 03 does not mention β€œsimilar” types in 3.10 / 15, so there may be a problem with C ++ 03, which seems to work with SNC.]

There is one more thing that needs to be checked, and whether it is necessary to initialize the data link in order to bind it to an object that has not yet been initialized ( m_data ). Intuitively, this seems OK, since a reference to an uninitialized m_data never converted to r. In any case, it is easily fixed.

+3
source

All Articles