C++ 仅更改常量的指针强制转换能否调用未定义的行为?
我无意中发现了一些似乎正确的代码。 它应该提供一个公共的、不可变的指针,同时保持可修改的非常量指针私有 很奇怪,这个代码在SN C++编译器上(PlayStation 3)中断了,但是在GCC上工作得很好。在SnC++中,<代码>数据< /代码>将指向伪值,而C++ 仅更改常量的指针强制转换能否调用未定义的行为?,c++,pointers,reference,C++,Pointers,Reference,我无意中发现了一些似乎正确的代码。 它应该提供一个公共的、不可变的指针,同时保持可修改的非常量指针私有 很奇怪,这个代码在SN C++编译器上(PlayStation 3)中断了,但是在GCC上工作得很好。在SnC++中,数据< /代码>将指向伪值,而 MyDATABAS/COD>将按预期工作。 有关守则: #include <cstdint> class Foo { public: Foo() : data((const std::uint8_t* const&
#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;
};
并查看生成的反汇编。请注意,它是PowerPC 64位,带有32位长字符和指针
序列号C++:ps3ppusnc-o测试序列号o-O3-C测试序列号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
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.4/4(C++11)中使用规范语言,但我相信3.10/10允许这样做。它说,对象可能被别名为“类似于对象动态类型的类型” 在这种情况下,对象的动态类型是
std::uint8\u t*
,类似的类型是const std::uint8\u t*const
。我想。自己检查4.4/4
[更新:C++03在3.10/15中没有提到“类似”类型,因此可能是您在C++03上遇到了麻烦,这大概就是SNC的工作原理。]
还有第二件事需要检查,那就是通过将引用
数据绑定到尚未初始化的对象(m_data
)来初始化引用数据是否可以。直观地看,这似乎还可以,因为对未初始化的m_数据的引用从未转换为右值。不管怎样,它很容易修复。什么是“发生断裂”的意思?您正在使用m_data
初始化data
,但在这一点上,m_data仍然没有初始化。您知道,我想我以前从未见过类似const type*const&
的东西。使用返回const std::uint8_t*
的访问器函数会更安全(因为它涉及的魔法更少)和更明智(对于阅读它的人来说),当然?使用访问器的@Rook肯定会更好:更地道,更可读,而且更自然。@SteveJessop No.该引用仅阻止定义编译器生成的复制赋值运算符。复制构造函数仍将生成。
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