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

このコードは未定義の動作を引き起こしますか? 私の知る限り、そのような参照へのキャストは に変換(const std::uint8_t* const&)m_dataされ*reinterpret_cast<const std::uint8_t* const*>(&m_data)ます。

テストケース:

Foo* new_foo() { return new Foo; }

生成された分解を見てください。これは 32 ビットの long とポインターを備えた 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
4

1 に答える 1

3

(C++11 の) 4.4/4 の仕様言語と戦わなければなりませんが、3.10/10 ではこれが可能になると思います。オブジェクトは「オブジェクトの動的な型に似た型」としてエイリアス化される可能性があると書かれています。

この場合、オブジェクトの動的タイプはstd::uint8_t*であり、同様のタイプはconst std::uint8_t* constです。おもう。4.4/4 を自分で確認してください。

[更新: C++03 は 3.10/15 で「類似の」型について言及していないため、おそらく SNC が動作する C++03 で問題が発生している可能性があります。]

2 番目にチェックする必要があるのは、dataまだ初期化されていないオブジェクトに参照をバインドして参照を初期化しても問題ないかどうかです ( m_data)。m_data初期化されていないものへの参照は右辺値に変換されないため、直感的には問題ないようです。とにかく簡単に直ります。

于 2012-06-15T13:37:01.693 に答える