у членов профсоюза не может быть конструкторов, но 'станд.:: пара' хорошо?

Для сценариев яблока я настроил специальный календарь iCal и предупреждения использования для выполнения их периодически. Для инструментов командной строки я использую launchd.

5
задан timrau 8 October 2012 в 16:06
поделиться

4 ответа

РЕДАКТИРОВАТЬ: Моя первоначальная позиция по std :: pair была неправильной, это не должно допускаться в объединении. Чтобы класс мог быть действительным членом объединения, он должен иметь тривиальный конструктор в соответствии со стандартом 9.5.1. Определение тривиального конструктора из параграфа 12.1.5:

Если не объявлено пользователем конструктор для класса X, по умолчанию конструктор объявлен неявно. неявно объявленное значение по умолчанию конструктор - это встроенный публичный член своего класса. Конструктор тривиальный если это неявно объявленный конструктор по умолчанию и если:

  • его класс не имеет виртуальных функций и виртуальных базовых классов, и
  • все прямые базовые классы его класса имеют тривиальные конструкторы, и
  • для всех нестатических членов данных его класса, которые относятся к классу (или их массив), каждый такой класс имеет тривиальный конструктор

В параграфе 20.2.2.2 говорится, что следующий конструктор должен быть доступен в паре:

pair(const T1& x, const T2& y);

, как только этот конструктор будет предоставлен, конструктор по умолчанию не будет неявно объявлен.

Самое забавное здесь то, что мой компилятор (Visual Studio 2008), похоже, уделяет особое внимание std :: pair . Если я скопирую код из реализации std :: pair и помещу его в свое собственное пространство имен foo, объединения не будут работать :)

namespace foo {
    template<class _Ty1, class _Ty2> struct pair {
        typedef _Ty1 first_type;
        typedef _Ty2 second_type;
        pair() : first(_Ty1()), second(_Ty2()) {
        }
    }
}

//This doesn't work in VC2008
union Baz {
    foo::pair<bool, double> a;
    int b;
}
//This works in VC2008
union Buz {
    std::pair<bool, double> a;
    int b;
}

Ваше решение - это обычный способ обойти эту проблему. Я обычно добавляю к имени класса C (сокращение от «конструкция»), чтобы частично имитировать синтаксис обычного конструктора, в вашем случае это будет CMyClass (a, b) .

Как отметили Стив и Матье, вы не используете очень хорошую хеш-функцию. Во-первых, нет реальной гарантии (я думаю, поправьте меня, если я ошибаюсь), что f и s в объединении будут даже частично занимать одно и то же пространство памяти, а во-вторых, даже если на практике они, вероятно, будут совместно использовать первые min (sizeof (s), sizeof (f)) байтов, это означает, что для MyClass вы хешируете только часть значения. В этом случае вы будете хешировать значение bool a , в этом случае есть два варианта:

  1. Ваш компилятор использует int в качестве внутреннего представления для bool , и в этом случае ваша хеш-функция будет возвращать только два значения: одно для истины и одно для ложного.
  2. Ваш компилятор использует char как внутреннее представление для bool .
10
ответ дан 18 December 2019 в 09:07
поделиться

I would replace this:

size_t hash() const {
    union {T f; size_t s;} u = { val };
    return u.s;
}

With this:

size_t hash() const {
    size_t s = 0;
    memcpy(&s, &val, std::min(sizeof(size_t), sizeof(T)));
    return s;
}

Copies the smaller of the two sizes rather than the larger, and if memcpy is an intrinsic on your compiler then you're looking good for optimisation. Most importantly, though, it doesn't matter what constructors T has.

It's not a good hash function, though, if T is a large type. In your example MyClass, you might find that bool and size_t are the same size in your implementation, hence the double doesn't participate in the hash at all so there are only two possible hashed values.

Still, it could be worse. If T has any virtual functions, you'll probably find that all instances hash to the same value: the address of the vtable...

4
ответ дан 18 December 2019 в 09:07
поделиться

Что касается использования std :: pair в качестве члена союза, я думаю, что это следует запретить. Стандарт гласит (§12.1):

Член объединения не должен относиться к типу класса (или его массиву), имеющему нетривиальный конструктор.

Таким образом, любой класс с определяемым пользователем конструктором не может использоваться в объединение, поскольку конструктор по умолчанию больше не будет неявно объявляться. Теперь в спецификации std :: pair (§20.2.2) явно указано, что реализации пар должны предоставлять параметризованный конструктор для инициализации обоих значений. Следовательно, либо реализация пары, либо реализация объединения, которую вы используете, не соответствует стандарту.

NB: Тестирование кода, который вы дали на Comeau, дает следующую ошибку:

"ComeauTest.c", line 8: error: invalid union member -- class
          "std::pair<bool, double>" has a disallowed member function
      union {T f; size_t s;} u = { val };
               ^
          detected during instantiation of "unsigned int Foo<T>::hash() const
                    [with T=std::pair<bool, double>]" at line 22
2
ответ дан 18 December 2019 в 09:07
поделиться

У меня только один вопрос: зачем использовать объединение?

Насколько я понимаю, хеш должен соответствовать первым байтам ваших объектов. Если вы собираетесь это сделать, почему бы и нет:

size_t hash() const {
  return reinterpret_cast<size_t>(val);
}

, который должен выполнить тот же трюк (я думаю) с большей эффективностью, поскольку в стеке нет выделения объекта размера sizeof (T) .

2
ответ дан 18 December 2019 в 09:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: