Простой класс хранения в C ++ и строгий псевдоним - PullRequest
2 голосов
/ 13 ноября 2010

У меня есть следующий код для небольшого класса для хранения.

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

gcc 4.4 предупреждает, что, когда я возвращаюсь, я нарушаю строгие правила наложения имен в storage::get().

AFAIK, я не нарушаю никаких правил.На самом ли деле я нарушаю строгий псевдоним или 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и up не выдает предупреждение - так что, очевидно, это было просто неверное истолкование строгих правил псевдонимов или ошибка в gcc 4.4.x

Ответы [ 2 ]

3 голосов
/ 21 июля 2012

На самом ли деле я нарушаю строгий псевдоним или gcc становится придирчивым?

Существует два различных толкования правила строгого алиасинга:

  • обычное правило слабого строгого псевдонима: (за исключением char / unsigned char типа) вы не можете использовать приведение или объединение для выполнения наказания типа , вам нужно memcpy (или два volatile доступы); такой код на самом деле не очень разумный и явно запрещен в C (кроме самого последнего, очень абсурдного стандарта C) и C ++.
  • необычное строгое строгое правило псевдонимов: вы не можете повторно использовать память: если область памяти имеет «динамический тип» (что?), Она не может использоваться с другим типом. Таким образом, вы просто не можете написать функцию-распределитель (malloc альтернатива) C, если только она не вызывает только malloc / free каждый раз.

Строгое правило плохо определено, нарушает множество разумного кода и по какой-то причине было выбрано сопровождающими GCC (основано исключительно на самообмане и круговых оправданиях - это действительно безобразно). Чтобы заставить код C ++ работать со строгой строгой оптимизацией псевдонимов, разработчики G ++ добавили пессимизацию для типичного кода C ++ (основанного на большей самообмане), чтобы сохранить оптимизацию!

Я не знаю, если / когда они осознают свою ошибку, в случае сомнений просто отключите строгий псевдоним . В любом случае, это очень незначительная оптимизация.

0 голосов
/ 13 ноября 2010

Для целей этого вопроса, строгое правило алиасинга гласит, по сути, что вы не должны обращаться к объекту, кроме как через указатель / ссылку его собственного типа или указатель / ссылку на тип символа (char или unsigned char).

В вашем коде у вас есть массив m_c элементов типа char, и вы пытаетесь получить к нему доступ через ссылку типа T. Это строгое нарушение псевдонимов.На некоторых более экзотических платформах это может иметь последствия, например, если m_c не выровнен должным образом для хранения элемента типа T.

...