ストレージ用の小さなクラスを持つための次のコードがあります。
#include <iostream>
template<typename T>
class storage
{
private:
struct destroy
{
T& m_t;
destroy(T& t) : m_t(t) { }
~destroy() { m_t.~T(); }
};
char m_c[sizeof(T)];
void* address() { return &m_c[0]; }
public:
void set(const T& t) { new (address()) T(t); }
T get()
{
T& t = *static_cast<T*>(address());
destroy _d(t);
return t;
}
};
template<typename T>
class choosable_storage
{
private:
union
{
T* m_p;
storage<T> m_storage;
};
bool m_direct;
public:
choosable_storage() : m_direct(false) { }
void set_direct(const T& t)
{
m_direct = true;
m_storage.set(t);
}
void set_indirect(T* const t) { m_p = t; }
T get()
{
if (m_direct) return m_storage.get();
return *m_p;
}
};
int main(void)
{
storage<int> s; // no problems
s.set(42);
std::cout << s.get() << std::endl;
int i = 10;
choosable_storage<int> c1; // strict aliasing warnings
c1.set_indirect(&i);
std::cout << c1.get() << std::endl;
choosable_storage<int> c2;
c2.set_direct(i);
std::cout << c2.get() << std::endl;
return 0;
}
storage::get()
gcc 4.4 は、戻ったときに厳密なエイリアシング規則を破っていることを警告しています。
私の知る限り、私はいかなる規則にも違反していません。私は実際に厳密なエイリアシングに違反していますか、それとも gcc はここでうるさくなっていますか?
そして、厳密なエイリアシングを無効にせずに警告を出さないようにする方法はありますか?
ありがとう
編集:
一方、次の実装では警告が表示されません。
template<typename T>
class storage
{
private:
struct destroy
{
T& m_t;
destroy(T& t) : m_t(t) { }
~destroy() { m_t.~T(); }
T const& operator()() const { return m_t; }
};
char m_c[sizeof(T)];
public:
void set(const T& t) { new(static_cast<void*>(m_c)) T(t); }
T get(void) { return destroy(*static_cast<T*>(static_cast<void*>(m_c)))(); }
};
編集:
gcc 4.5 以降は警告を発行しません。つまり、これは厳密なエイリアシング ルールの誤解か、gcc 4.4.x のバグであったようです。